Update copyright dates.
[gcc.git] / gcc / gcc.c
index eaa4653227012834940b55ad2ef67620727c07b8..42077fb7404b9f0dfd548d23200043a580f7d1ab 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -1,5 +1,5 @@
 /* Compiler driver program that can handle many languages.
-   Copyright (C) 1987-2016 Free Software Foundation, Inc.
+   Copyright (C) 1987-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -36,11 +36,11 @@ compilation is specified by a string called a "spec".  */
 #include "obstack.h"
 #include "intl.h"
 #include "prefix.h"
+#include "opt-suggestions.h"
 #include "gcc.h"
 #include "diagnostic.h"
 #include "flags.h"
 #include "opts.h"
-#include "params.h"
 #include "filenames.h"
 #include "spellcheck.h"
 
@@ -56,7 +56,7 @@ compilation is specified by a string called a "spec".  */
      getenv ();
    Hence we need to use "get" for the accessor method, not "getenv".  */
 
-class env_manager
+struct env_manager
 {
  public:
   void init (bool can_restore, bool debug);
@@ -170,9 +170,10 @@ env_manager::restore ()
 \f
 
 /* By default there is no special suffix for target executables.  */
-/* FIXME: when autoconf is fixed, remove the host check - dj */
-#if defined(TARGET_EXECUTABLE_SUFFIX) && defined(HOST_EXECUTABLE_SUFFIX)
+#ifdef TARGET_EXECUTABLE_SUFFIX
 #define HAVE_TARGET_EXECUTABLE_SUFFIX
+#else
+#define TARGET_EXECUTABLE_SUFFIX ""
 #endif
 
 /* By default there is no special suffix for host executables.  */
@@ -219,6 +220,10 @@ static int print_help_list;
 
 static int print_version;
 
+/* Flag that stores string prefix for which we provide bash completion.  */
+
+static const char *completion = NULL;
+
 /* Flag indicating whether we should ONLY print the command and
    arguments (like verbose_flag) without executing the command.
    Displayed arguments are quoted so that the generated command
@@ -265,12 +270,36 @@ static const char *target_sysroot_hdrs_suffix = 0;
 static enum save_temps {
   SAVE_TEMPS_NONE,             /* no -save-temps */
   SAVE_TEMPS_CWD,              /* -save-temps in current directory */
+  SAVE_TEMPS_DUMP,              /* -save-temps in dumpdir */
   SAVE_TEMPS_OBJ               /* -save-temps in object directory */
 } save_temps_flag;
 
-/* Output file to use to get the object directory for -save-temps=obj  */
-static char *save_temps_prefix = 0;
-static size_t save_temps_length = 0;
+/* Set this iff the dumppfx implied by a -save-temps=* option is to
+   override a -dumpdir option, if any.  */
+static bool save_temps_overrides_dumpdir = false;
+
+/* -dumpdir, -dumpbase and -dumpbase-ext flags passed in, possibly
+   rearranged as they are to be passed down, e.g., dumpbase and
+   dumpbase_ext may be cleared if integrated with dumpdir or
+   dropped.  */
+static char *dumpdir, *dumpbase, *dumpbase_ext;
+
+/* Usually the length of the string in dumpdir.  However, during
+   linking, it may be shortened to omit a driver-added trailing dash,
+   by then replaced with a trailing period, that is still to be passed
+   to sub-processes in -dumpdir, but not to be generally used in spec
+   filename expansions.  See maybe_run_linker.  */
+static size_t dumpdir_length = 0;
+
+/* Set if the last character in dumpdir is (or was) a dash that the
+   driver added to dumpdir after dumpbase or linker output name.  */
+static bool dumpdir_trailing_dash_added = false;
+
+/* Basename of dump and aux outputs, computed from dumpbase (given or
+   derived from output name), to override input_basename in non-%w %b
+   et al.  */
+static char *outbase;
+static size_t outbase_length = 0;
 
 /* The compiler version.  */
 
@@ -349,24 +378,23 @@ static inline void mark_matching_switches (const char *, const char *, int);
 static inline void process_marked_switches (void);
 static const char *process_brace_body (const char *, const char *, const char *, int, int);
 static const struct spec_function *lookup_spec_function (const char *);
-static const char *eval_spec_function (const char *, const char *);
-static const char *handle_spec_function (const char *, bool *);
+static const char *eval_spec_function (const char *, const char *, const char *);
+static const char *handle_spec_function (const char *, bool *, const char *);
 static char *save_string (const char *, int);
 static void set_collect_gcc_options (void);
 static int do_spec_1 (const char *, int, const char *);
-static int do_spec_2 (const char *);
+static int do_spec_2 (const char *, const char *);
 static void do_option_spec (const char *, const char *);
 static void do_self_spec (const char *);
 static const char *find_file (const char *);
 static int is_directory (const char *, bool);
-static const char *validate_switches (const char *, bool);
+static const char *validate_switches (const char *, bool, bool);
 static void validate_all_switches (void);
 static inline void validate_switches_from_spec (const char *, bool);
 static void give_switch (int, int);
 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 display_help (void);
 static void add_preprocessor_option (const char *, int);
 static void add_assembler_option (const char *, int);
@@ -388,6 +416,7 @@ static void try_generate_repro (const char **argv);
 static const char *getenv_spec_function (int, const char **);
 static const char *if_exists_spec_function (int, const char **);
 static const char *if_exists_else_spec_function (int, const char **);
+static const char *if_exists_then_else_spec_function (int, const char **);
 static const char *sanitize_spec_function (int, const char **);
 static const char *replace_outfile_spec_function (int, const char **);
 static const char *remove_outfile_spec_function (int, const char **);
@@ -398,11 +427,17 @@ static const char *find_plugindir_spec_function (int, const char **);
 static const char *print_asm_header_spec_function (int, const char **);
 static const char *compare_debug_dump_opt_spec_function (int, const char **);
 static const char *compare_debug_self_opt_spec_function (int, const char **);
-static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
 static const char *pass_through_libs_spec_func (int, const char **);
-static const char *replace_extension_spec_func (int, const char **);
+static const char *dumps_spec_func (int, const char **);
 static const char *greater_than_spec_func (int, const char **);
+static const char *debug_level_greater_than_spec_func (int, const char **);
+static const char *dwarf_version_greater_than_spec_func (int, const char **);
+static const char *find_fortran_preinclude_file (int, const char **);
 static char *convert_white_space (char *);
+static char *quote_spec (char *);
+static char *quote_spec_arg (char *);
+static bool not_actual_file_p (const char *);
+
 \f
 /* The Specs Language
 
@@ -420,12 +455,19 @@ expanding these sequences; therefore, you can concatenate them together
 or with constant text in a single argument.
 
  %%    substitute one % into the program name or argument.
+ %"     substitute an empty argument.
  %i     substitute the name of the input file being processed.
- %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.
- %B    same as %b, but include the file suffix (text after the last period).
+ %b     substitute the basename for outputs related with the input file
+       being processed.  This is often a substring of the input file name,
+       up to (and not including) the last period but, unless %w is active,
+       it is affected by the directory selected by -save-temps=*, by
+       -dumpdir, and, in case of multiple compilations, even by -dumpbase
+       and -dumpbase-ext and, in case of linking, by the linker output
+       name.  When %w is active, it derives the main output name only from
+       the input file base name; when it is not, it names aux/dump output
+       file.
+ %B    same as %b, but include the input file suffix (text after the last
+       period).
  %gSUFFIX
        substitute a file name that has suffix SUFFIX and is chosen
        once per compilation, and mark the argument a la %d.  To reduce
@@ -474,8 +516,11 @@ or with constant text in a single argument.
        into the sequence of arguments that %o will substitute later.
  %V    indicates that this compilation produces no "output file".
  %W{...}
-       like %{...} but mark last argument supplied within
-       as a file to be deleted on failure.
+       like %{...} but marks the last argument supplied within as a file
+       to be deleted on failure.
+ %@{...}
+       like %{...} but puts the result into a FILE and substitutes @FILE
+       if an @file argument has been supplied.
  %o    substitutes the names of all the output files, with spaces
        automatically placed around them.  You should write spaces
        around the %o as well or the results are undefined.
@@ -497,6 +542,12 @@ or with constant text in a single argument.
  %s     current argument is the name of a library or startup file of some sort.
         Search for that file in a standard list of directories
        and substitute the full name found.
+ %T    current argument is the name of a linker script.
+       Search for that file in the current list of directories to scan for
+       libraries.  If the file is located, insert a --script option into the
+       command line followed by the full path name found.  If the file is
+       not found then generate an error message.
+       Note: the current working directory is not searched.
  %eSTR  Print STR as an error message.  STR is terminated by a newline.
         Use this when inconsistent options are detected.
  %nSTR  Print STR as a notice.  STR is terminated by a newline.
@@ -583,6 +634,12 @@ or with constant text in a single argument.
 
  %(Spec) processes a specification defined in a specs file as *Spec:
 
+The switch matching text S in a %{S}, %{S:X}, or similar construct can use
+a backslash to ignore the special meaning of the character following it,
+thus allowing literal matching of a character that is otherwise specially
+treated.  For example, %{std=iso9899\:1999:X} substitutes X if the
+-std=iso9899:1999 option is given.
+
 The conditional text X in a %{S:X} or similar construct may contain
 other nested % constructs or spaces, or even newlines.  They are
 processed as usual, as described above.  Trailing white space in X is
@@ -626,10 +683,10 @@ proper position among the other output files.  */
 #define ASM_FINAL_SPEC \
   "%{gsplit-dwarf: \n\
        objcopy --extract-dwo \
-        %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
-        %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
+        %{c:%{o*:%*}%{!o*:%w%b%O}}%{!c:%U%O} \
+        %b.dwo \n\
        objcopy --strip-dwo \
-        %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
+        %{c:%{o*:%*}%{!o*:%w%b%O}}%{!c:%U%O} \
     }"
 #endif
 
@@ -676,7 +733,7 @@ proper position among the other output files.  */
 
 #ifndef LIBASAN_SPEC
 #define STATIC_LIBASAN_LIBS \
-  " %{static-libasan:%:include(libsanitizer.spec)%(link_libasan)}"
+  " %{static-libasan|static:%:include(libsanitizer.spec)%(link_libasan)}"
 #ifdef LIBASAN_EARLY_SPEC
 #define LIBASAN_SPEC STATIC_LIBASAN_LIBS
 #elif defined(HAVE_LD_STATIC_DYNAMIC)
@@ -692,9 +749,27 @@ proper position among the other output files.  */
 #define LIBASAN_EARLY_SPEC ""
 #endif
 
+#ifndef LIBHWASAN_SPEC
+#define STATIC_LIBHWASAN_LIBS \
+  " %{static-libhwasan|static:%:include(libsanitizer.spec)%(link_libhwasan)}"
+#ifdef LIBHWASAN_EARLY_SPEC
+#define LIBHWASAN_SPEC STATIC_LIBHWASAN_LIBS
+#elif defined(HAVE_LD_STATIC_DYNAMIC)
+#define LIBHWASAN_SPEC "%{static-libhwasan:" LD_STATIC_OPTION \
+                    "} -lhwasan %{static-libhwasan:" LD_DYNAMIC_OPTION "}" \
+                    STATIC_LIBHWASAN_LIBS
+#else
+#define LIBHWASAN_SPEC "-lhwasan" STATIC_LIBHWASAN_LIBS
+#endif
+#endif
+
+#ifndef LIBHWASAN_EARLY_SPEC
+#define LIBHWASAN_EARLY_SPEC ""
+#endif
+
 #ifndef LIBTSAN_SPEC
 #define STATIC_LIBTSAN_LIBS \
-  " %{static-libtsan:%:include(libsanitizer.spec)%(link_libtsan)}"
+  " %{static-libtsan|static:%:include(libsanitizer.spec)%(link_libtsan)}"
 #ifdef LIBTSAN_EARLY_SPEC
 #define LIBTSAN_SPEC STATIC_LIBTSAN_LIBS
 #elif defined(HAVE_LD_STATIC_DYNAMIC)
@@ -712,7 +787,7 @@ proper position among the other output files.  */
 
 #ifndef LIBLSAN_SPEC
 #define STATIC_LIBLSAN_LIBS \
-  " %{static-liblsan:%:include(libsanitizer.spec)%(link_liblsan)}"
+  " %{static-liblsan|static:%:include(libsanitizer.spec)%(link_liblsan)}"
 #ifdef LIBLSAN_EARLY_SPEC
 #define LIBLSAN_SPEC STATIC_LIBLSAN_LIBS
 #elif defined(HAVE_LD_STATIC_DYNAMIC)
@@ -730,7 +805,7 @@ proper position among the other output files.  */
 
 #ifndef LIBUBSAN_SPEC
 #define STATIC_LIBUBSAN_LIBS \
-  " %{static-libubsan:%:include(libsanitizer.spec)%(link_libubsan)}"
+  " %{static-libubsan|static:%:include(libsanitizer.spec)%(link_libubsan)}"
 #ifdef HAVE_LD_STATIC_DYNAMIC
 #define LIBUBSAN_SPEC "%{static-libubsan:" LD_STATIC_OPTION \
                     "} -lubsan %{static-libubsan:" LD_DYNAMIC_OPTION "}" \
@@ -827,20 +902,39 @@ proper position among the other output files.  */
 #endif /* HAVE_LD_COMPRESS_DEBUG >= 2 */
 
 /* Define ASM_DEBUG_SPEC to be a spec suitable for translating '-g'
-   to the assembler.  */
+   to the assembler, when compiling assembly sources only.  */
 #ifndef ASM_DEBUG_SPEC
+# if defined(HAVE_AS_GDWARF_5_DEBUG_FLAG) && defined(HAVE_AS_WORKING_DWARF_N_FLAG)
+/* If --gdwarf-N is supported and as can handle even compiler generated
+   .debug_line with it, supply --gdwarf-N in ASM_DEBUG_OPTION_SPEC rather
+   than in ASM_DEBUG_SPEC, so that it applies to both .s and .c etc.
+   compilations.  */
+#  define ASM_DEBUG_DWARF_OPTION ""
+# elif defined(HAVE_AS_GDWARF_5_DEBUG_FLAG)
+#  define ASM_DEBUG_DWARF_OPTION "%{%:dwarf-version-gt(4):--gdwarf-5;" \
+       "%:dwarf-version-gt(3):--gdwarf-4;"                             \
+       "%:dwarf-version-gt(2):--gdwarf-3;"                             \
+       ":--gdwarf2}"
+# else
+#  define ASM_DEBUG_DWARF_OPTION "--gdwarf2"
+# endif
 # if defined(DBX_DEBUGGING_INFO) && defined(DWARF2_DEBUGGING_INFO) \
      && defined(HAVE_AS_GDWARF2_DEBUG_FLAG) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
 #  define ASM_DEBUG_SPEC                                               \
       (PREFERRED_DEBUGGING_TYPE == DBX_DEBUG                           \
-       ? "%{!g0:%{gdwarf*:--gdwarf2}%{!gdwarf*:%{g*:--gstabs}}}" ASM_MAP       \
-       : "%{!g0:%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}}" ASM_MAP)
+       ? "%{%:debug-level-gt(0):"                                      \
+        "%{gdwarf*:" ASM_DEBUG_DWARF_OPTION "};"                       \
+        ":%{g*:--gstabs}}" ASM_MAP                                     \
+       : "%{%:debug-level-gt(0):"                                      \
+        "%{gstabs*:--gstabs;"                                          \
+        ":%{g*:" ASM_DEBUG_DWARF_OPTION "}}}" ASM_MAP)
 # else
 #  if defined(DBX_DEBUGGING_INFO) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
-#   define ASM_DEBUG_SPEC "%{g*:%{!g0:--gstabs}}" ASM_MAP
+#   define ASM_DEBUG_SPEC "%{g*:%{%:debug-level-gt(0):--gstabs}}" ASM_MAP
 #  endif
 #  if defined(DWARF2_DEBUGGING_INFO) && defined(HAVE_AS_GDWARF2_DEBUG_FLAG)
-#   define ASM_DEBUG_SPEC "%{g*:%{!g0:--gdwarf2}}" ASM_MAP
+#   define ASM_DEBUG_SPEC "%{g*:%{%:debug-level-gt(0):" \
+       ASM_DEBUG_DWARF_OPTION "}}" ASM_MAP
 #  endif
 # endif
 #endif
@@ -848,13 +942,39 @@ proper position among the other output files.  */
 # define ASM_DEBUG_SPEC ""
 #endif
 
+/* Define ASM_DEBUG_OPTION_SPEC to be a spec suitable for translating '-g'
+   to the assembler when compiling all sources.  */
+#ifndef ASM_DEBUG_OPTION_SPEC
+# if defined(HAVE_AS_GDWARF_5_DEBUG_FLAG) && defined(HAVE_AS_WORKING_DWARF_N_FLAG)
+#  define ASM_DEBUG_OPTION_DWARF_OPT                                   \
+       "%{%:dwarf-version-gt(4):--gdwarf-5 ;"                          \
+       "%:dwarf-version-gt(3):--gdwarf-4 ;"                            \
+       "%:dwarf-version-gt(2):--gdwarf-3 ;"                            \
+       ":--gdwarf2 }"
+#  if defined(DBX_DEBUGGING_INFO) && defined(DWARF2_DEBUGGING_INFO)
+#  define ASM_DEBUG_OPTION_SPEC                                                \
+      (PREFERRED_DEBUGGING_TYPE == DBX_DEBUG                           \
+       ? "%{%:debug-level-gt(0):"                                      \
+        "%{gdwarf*:" ASM_DEBUG_OPTION_DWARF_OPT "}}"                   \
+       : "%{%:debug-level-gt(0):"                                      \
+        "%{!gstabs*:%{g*:" ASM_DEBUG_OPTION_DWARF_OPT "}}}")
+# elif defined(DWARF2_DEBUGGING_INFO)
+#   define ASM_DEBUG_OPTION_SPEC "%{g*:%{%:debug-level-gt(0):" \
+       ASM_DEBUG_OPTION_DWARF_OPT "}}"
+#  endif
+# endif
+#endif
+#ifndef ASM_DEBUG_OPTION_SPEC
+# define ASM_DEBUG_OPTION_SPEC ""
+#endif
+
 /* Here is the spec for running the linker, after compiling all files.  */
 
 /* This is overridable by the target in case they need to specify the
    -lgcc and -lc order specially, yet not require them to override all
    of LINK_COMMAND_SPEC.  */
 #ifndef LINK_GCC_C_SEQUENCE_SPEC
-#define LINK_GCC_C_SEQUENCE_SPEC "%G %L %G"
+#define LINK_GCC_C_SEQUENCE_SPEC "%G %{!nolibc:%L %G}"
 #endif
 
 #ifndef LINK_SSP_SPEC
@@ -869,8 +989,7 @@ proper position among the other output files.  */
 #endif
 
 #ifdef ENABLE_DEFAULT_PIE
-#define NO_PIE_SPEC            "no-pie|static"
-#define PIE_SPEC               NO_PIE_SPEC "|r|shared:;"
+#define PIE_SPEC               "!no-pie"
 #define NO_FPIE1_SPEC          "fno-pie"
 #define FPIE1_SPEC             NO_FPIE1_SPEC ":;"
 #define NO_FPIE2_SPEC          "fno-PIE"
@@ -891,7 +1010,6 @@ proper position among the other output files.  */
 #define FPIE_OR_FPIC_SPEC      NO_FPIE_AND_FPIC_SPEC ":;"
 #else
 #define PIE_SPEC               "pie"
-#define NO_PIE_SPEC            PIE_SPEC "|r|shared:;"
 #define FPIE1_SPEC             "fpie"
 #define NO_FPIE1_SPEC          FPIE1_SPEC ":;"
 #define FPIE2_SPEC             "fPIE"
@@ -920,7 +1038,7 @@ proper position among the other output files.  */
 #else
 #define LD_PIE_SPEC ""
 #endif
-#define LINK_PIE_SPEC "%{no-pie:} " "%{" PIE_SPEC ":" LD_PIE_SPEC "} "
+#define LINK_PIE_SPEC "%{static|shared|r:;" PIE_SPEC ":" LD_PIE_SPEC "} "
 #endif
 
 #ifndef LINK_BUILDID_SPEC
@@ -929,6 +1047,10 @@ proper position among the other output files.  */
 # endif
 #endif
 
+#ifndef LTO_PLUGIN_SPEC
+#define LTO_PLUGIN_SPEC ""
+#endif
+
 /* Conditional to test whether the LTO plugin is used or not.
    FIXME: For slim LTO we will need to enable plugin unconditionally.  This
    still cause problems with PLUGIN_LD != LD and when plugin is built but
@@ -953,6 +1075,8 @@ proper position among the other output files.  */
     -plugin %(linker_plugin_file) \
     -plugin-opt=%(lto_wrapper) \
     -plugin-opt=-fresolution=%u.res \
+    " LTO_PLUGIN_SPEC "\
+    %{flinker-output=*:-plugin-opt=-linker-output-known} \
     %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} \
     }" PLUGIN_COND_CLOSE
 #else
@@ -964,20 +1088,23 @@ proper position among the other output files.  */
 /* Linker command line options for -fsanitize= early on the command line.  */
 #ifndef SANITIZER_EARLY_SPEC
 #define SANITIZER_EARLY_SPEC "\
-%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_EARLY_SPEC "} \
+%{!nostdlib:%{!r:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_EARLY_SPEC "} \
+    %{%:sanitize(hwaddress):" LIBHWASAN_EARLY_SPEC "} \
     %{%:sanitize(thread):" LIBTSAN_EARLY_SPEC "} \
-    %{%:sanitize(leak):" LIBLSAN_EARLY_SPEC "}}}"
+    %{%:sanitize(leak):" LIBLSAN_EARLY_SPEC "}}}}"
 #endif
 
 /* Linker command line options for -fsanitize= late on the command line.  */
 #ifndef SANITIZER_SPEC
 #define SANITIZER_SPEC "\
-%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_SPEC "\
+%{!nostdlib:%{!r:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_SPEC "\
     %{static:%ecannot specify -static with -fsanitize=address}}\
+    %{%:sanitize(hwaddress):" LIBHWASAN_SPEC "\
+       %{static:%ecannot specify -static with -fsanitize=hwaddress}}\
     %{%:sanitize(thread):" LIBTSAN_SPEC "\
     %{static:%ecannot specify -static with -fsanitize=thread}}\
     %{%:sanitize(undefined):" LIBUBSAN_SPEC "}\
-    %{%:sanitize(leak):" LIBLSAN_SPEC "}}}"
+    %{%:sanitize(leak):" LIBLSAN_SPEC "}}}}"
 #endif
 
 #ifndef POST_LINK_SPEC
@@ -989,18 +1116,26 @@ proper position among the other output files.  */
     the vtable verification runtime functions are in libstdc++, so we use
     the spec just below this one.  */
 #ifndef VTABLE_VERIFICATION_SPEC
+#if ENABLE_VTABLE_VERIFY
+#define VTABLE_VERIFICATION_SPEC "\
+%{!nostdlib:%{!r:%{fvtable-verify=std: -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end}\
+    %{fvtable-verify=preinit: -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end}}}"
+#else
 #define VTABLE_VERIFICATION_SPEC "\
-%{!nostdlib:%{fvtable-verify=std: -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end}\
-    %{fvtable-verify=preinit: -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end}}"
+%{fvtable-verify=none:} \
+%{fvtable-verify=std: \
+  %e-fvtable-verify=std is not supported in this configuration} \
+%{fvtable-verify=preinit: \
+  %e-fvtable-verify=preinit is not supported in this configuration}"
 #endif
-
-#ifndef CHKP_SPEC
-#define CHKP_SPEC ""
 #endif
 
 /* -u* was put back because both BSD and SysV seem to support it.  */
-/* %{static:} simply prevents an error message if the target machine
-   doesn't handle -static.  */
+/* %{static|no-pie|static-pie:} simply prevents an error message:
+   1. If the target machine doesn't handle -static.
+   2. If PIE isn't enabled by default.
+   3. If the target machine doesn't handle -static-pie.
+ */
 /* 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.  */
@@ -1016,17 +1151,16 @@ proper position among the other output files.  */
     %{flto} %{fno-lto} %{flto=*} %l " LINK_PIE_SPEC \
    "%{fuse-ld=*:-fuse-ld=%*} " LINK_COMPRESS_DEBUG_SPEC \
    "%X %{o*} %{e*} %{N} %{n} %{r}\
-    %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}} \
-    %{static:} %{L*} %(mfwrap) %(link_libgcc) " \
-    VTABLE_VERIFICATION_SPEC " " SANITIZER_EARLY_SPEC " %o " CHKP_SPEC " \
-    %{fopenacc|fopenmp|%:gt(%{ftree-parallelize-loops=*} 1):\
+    %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!r:%{!nostartfiles:%S}}} \
+    %{static|no-pie|static-pie:} %@{L*} %(mfwrap) %(link_libgcc) " \
+    VTABLE_VERIFICATION_SPEC " " SANITIZER_EARLY_SPEC " %o "" \
+    %{fopenacc|fopenmp|%:gt(%{ftree-parallelize-loops=*:%*} 1):\
        %:include(libgomp.spec)%(link_gomp)}\
-    %{fcilkplus:%:include(libcilkrts.spec)%(link_cilkrts)}\
     %{fgnu-tm:%:include(libitm.spec)%(link_itm)}\
     %(mflib) " STACK_SPLIT_SPEC "\
     %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} " SANITIZER_SPEC " \
-    %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
-    %{!nostdlib:%{!nostartfiles:%E}} %{T*}  \n%(post_link) }}}}}}"
+    %{!nostdlib:%{!r:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}}\
+    %{!nostdlib:%{!r:%{!nostartfiles:%E}}} %{T*}  \n%(post_link) }}}}}}"
 #endif
 
 #ifndef LINK_LIBGCC_SPEC
@@ -1051,6 +1185,7 @@ proper position among the other output files.  */
 #endif
 
 static const char *asm_debug = ASM_DEBUG_SPEC;
+static const char *asm_debug_option = ASM_DEBUG_OPTION_SPEC;
 static const char *cpp_spec = CPP_SPEC;
 static const char *cc1_spec = CC1_SPEC;
 static const char *cc1plus_spec = CC1PLUS_SPEC;
@@ -1093,12 +1228,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 =
-"%{!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*}\
+ %{Mmodules} %{Mno-modules}\
  %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}}\
- %{remap} %{g3|ggdb3|gstabs3|gcoff3|gxcoff3|gvms3:-dD}\
+ %{remap} %{%:debug-level-gt(2):-dD}\
  %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
  %{H} %C %{D*&U*&A*} %{i*} %Z %i\
  %{E|M|MM:%W{o*}}";
@@ -1110,29 +1246,38 @@ static const char *cpp_unique_options =
    in turn cause preprocessor symbols to be defined specially.  */
 static const char *cpp_options =
 "%(cpp_unique_options) %1 %{m*} %{std*&ansi&trigraphs} %{W*&pedantic*} %{w}\
- %{f*} %{g*:%{!g0:%{g*} %{!fno-working-directory:-fworking-directory}}} %{O*}\
+ %{f*} %{g*:%{%:debug-level-gt(0):%{g*}\
+ %{!fno-working-directory:-fworking-directory}}} %{O*}\
  %{undef} %{save-temps*:-fpch-preprocess}";
 
+/* Pass -d* flags, possibly modifying -dumpdir, -dumpbase et al.
+
+   Make it easy for a language to override the argument for the
+   %:dumps specs function call.  */
+#define DUMPS_OPTIONS(EXTS) \
+  "%<dumpdir %<dumpbase %<dumpbase-ext %{d*} %:dumps(" EXTS ")"
+
 /* This contains cpp options which are not passed when the preprocessor
    output will be used by another program.  */
-static const char *cpp_debug_options = "%{d*}";
+static const char *cpp_debug_options = DUMPS_OPTIONS ("");
 
 /* NB: This is shared amongst all front-ends, except for Ada.  */
 static const char *cc1_options =
 "%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
  %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
- %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{aux-info*}\
- %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} \
- %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \
+ %1 %{!Q:-quiet} %(cpp_debug_options) %{m*} %{aux-info*}\
  %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs}\
  %{v:-version} %{pg:-p} %{p} %{f*} %{undef}\
  %{Qn:-fno-ident} %{Qy:} %{-help:--help}\
  %{-target-help:--target-help}\
  %{-version:--version}\
  %{-help=*:--help=%*}\
- %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
+ %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %w%b.s}}}\
  %{fsyntax-only:-o %j} %{-param*}\
- %{coverage:-fprofile-arcs -ftest-coverage}";
+ %{coverage:-fprofile-arcs -ftest-coverage}\
+ %{fprofile-arcs|fprofile-generate*|coverage:\
+   %{!fprofile-update=single:\
+     %{pthread:-fprofile-update=prefer-atomic}}}";
 
 static const char *asm_options =
 "%{-target-help:%:print-asm-header()} "
@@ -1141,6 +1286,7 @@ static const char *asm_options =
    to the assembler equivalents.  */
 "%{v} %{w:-W} %{I*} "
 #endif
+"%(asm_debug_option)"
 ASM_COMPRESS_DEBUG_SPEC
 "%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}";
 
@@ -1183,7 +1329,7 @@ static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
    for targets that use different start files and suchlike.  */
 #ifndef GOMP_SELF_SPECS
 #define GOMP_SELF_SPECS \
-  "%{fopenacc|fopenmp|%:gt(%{ftree-parallelize-loops=*} 1): " \
+  "%{fopenacc|fopenmp|%:gt(%{ftree-parallelize-loops=*:%*} 1): " \
   "-pthread}"
 #endif
 
@@ -1192,15 +1338,9 @@ static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
 #define GTM_SELF_SPECS "%{fgnu-tm: -pthread}"
 #endif
 
-/* Likewise for -fcilkplus.  */
-#ifndef CILK_SELF_SPECS
-#define CILK_SELF_SPECS "%{fcilkplus: -pthread}"
-#endif
-
 static const char *const driver_self_specs[] = {
   "%{fdump-final-insns:-fdump-final-insns=.} %<fdump-final-insns",
-  DRIVER_SELF_SPECS, CONFIGURE_SPECS, GOMP_SELF_SPECS, GTM_SELF_SPECS,
-  CILK_SELF_SPECS
+  DRIVER_SELF_SPECS, CONFIGURE_SPECS, GOMP_SELF_SPECS, GTM_SELF_SPECS
 };
 
 #ifndef OPTION_DEFAULT_SPECS
@@ -1237,9 +1377,9 @@ struct compiler
   const char *cpp_spec;         /* If non-NULL, substitute this spec
                                   for `%C', rather than the usual
                                   cpp_spec.  */
-  const int combinable;          /* If nonzero, compiler can deal with
+  int combinable;               /* If nonzero, compiler can deal with
                                    multiple source files at once (IMA).  */
-  const int needs_preprocessing; /* If nonzero, source files need to
+  int needs_preprocessing;       /* If nonzero, source files need to
                                    be run through a preprocessor.  */
 };
 
@@ -1283,10 +1423,8 @@ static const struct compiler default_compilers[] =
   {".f03", "#Fortran", 0, 0, 0}, {".F03", "#Fortran", 0, 0, 0},
   {".f08", "#Fortran", 0, 0, 0}, {".F08", "#Fortran", 0, 0, 0},
   {".r", "#Ratfor", 0, 0, 0},
-  {".p", "#Pascal", 0, 0, 0}, {".pas", "#Pascal", 0, 0, 0},
-  {".java", "#Java", 0, 0, 0}, {".class", "#Java", 0, 0, 0},
-  {".zip", "#Java", 0, 0, 0}, {".jar", "#Java", 0, 0, 0},
   {".go", "#Go", 0, 1, 0},
+  {".d", "#D", 0, 1, 0}, {".dd", "#D", 0, 1, 0}, {".di", "#D", 0, 1, 0},
   /* Next come the entries for C.  */
   {".c", "@c", 0, 0, 1},
   {"@c",
@@ -1316,12 +1454,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)\
-                       %{!fsyntax-only:-o %g.s \
+                       %{!fsyntax-only:%{!S:-o %g.s} \
                            %{!fdump-ada-spec*:%{!o*:--output-pch=%i.gch}\
                                               %W{o*:--output-pch=%*}}%V}}\
          %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\
                cc1 %(cpp_unique_options) %(cc1_options)\
-                   %{!fsyntax-only:-o %g.s \
+                   %{!fsyntax-only:%{!S:-o %g.s} \
                        %{!fdump-ada-spec*:%{!o*:--output-pch=%i.gch}\
                                           %W{o*:--output-pch=%*}}%V}}}}}}}", 0, 0, 0},
   {".i", "@cpp-output", 0, 0, 0},
@@ -1545,6 +1683,7 @@ static struct spec_list static_specs[] =
 {
   INIT_STATIC_SPEC ("asm",                     &asm_spec),
   INIT_STATIC_SPEC ("asm_debug",               &asm_debug),
+  INIT_STATIC_SPEC ("asm_debug_option",                &asm_debug_option),
   INIT_STATIC_SPEC ("asm_final",               &asm_final_spec),
   INIT_STATIC_SPEC ("asm_options",             &asm_options),
   INIT_STATIC_SPEC ("invoke_as",               &invoke_as),
@@ -1613,6 +1752,7 @@ static const struct spec_function static_spec_functions[] =
   { "getenv",                   getenv_spec_function },
   { "if-exists",               if_exists_spec_function },
   { "if-exists-else",          if_exists_else_spec_function },
+  { "if-exists-then-else",     if_exists_then_else_spec_function },
   { "sanitize",                        sanitize_spec_function },
   { "replace-outfile",         replace_outfile_spec_function },
   { "remove-outfile",          remove_outfile_spec_function },
@@ -1623,10 +1763,12 @@ static const struct spec_function static_spec_functions[] =
   { "print-asm-header",                print_asm_header_spec_function },
   { "compare-debug-dump-opt",  compare_debug_dump_opt_spec_function },
   { "compare-debug-self-opt",  compare_debug_self_opt_spec_function },
-  { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
   { "pass-through-libs",       pass_through_libs_spec_func },
-  { "replace-extension",       replace_extension_spec_func },
+  { "dumps",                    dumps_spec_func },
   { "gt",                      greater_than_spec_func },
+  { "debug-level-gt",          debug_level_greater_than_spec_func },
+  { "dwarf-version-gt",                dwarf_version_greater_than_spec_func },
+  { "fortran-preinclude-file", find_fortran_preinclude_file},
 #ifdef EXTRA_SPEC_FUNCTIONS
   EXTRA_SPEC_FUNCTIONS
 #endif
@@ -1650,17 +1792,19 @@ init_gcc_specs (struct obstack *obstack, const char *shared_name,
 {
   char *buf;
 
-  buf = concat ("%{static|static-libgcc:", static_name, " ", eh_name, "}"
-               "%{!static:%{!static-libgcc:"
 #if USE_LD_AS_NEEDED
+  buf = concat ("%{static|static-libgcc|static-pie:", static_name, " ", eh_name, "}"
+               "%{!static:%{!static-libgcc:%{!static-pie:"
                "%{!shared-libgcc:",
                static_name, " " LD_AS_NEEDED_OPTION " ",
                shared_name, " " LD_NO_AS_NEEDED_OPTION
                "}"
                "%{shared-libgcc:",
                shared_name, "%{!shared: ", static_name, "}"
-               "}"
+               "}}"
 #else
+  buf = concat ("%{static|static-libgcc:", static_name, " ", eh_name, "}"
+               "%{!static:%{!static-libgcc:"
                "%{!shared:"
                "%{!shared-libgcc:", static_name, " ", eh_name, "}"
                "%{shared-libgcc:", shared_name, " ", static_name, "}"
@@ -1768,8 +1912,8 @@ init_spec (void)
                            "-lgcc_eh"
 #ifdef USE_LIBUNWIND_EXCEPTIONS
 # ifdef HAVE_LD_STATIC_DYNAMIC
-                           " %{!static:" LD_STATIC_OPTION "} -lunwind"
-                           " %{!static:" LD_DYNAMIC_OPTION "}"
+                           " %{!static:%{!static-pie:" LD_STATIC_OPTION "}} -lunwind"
+                           " %{!static:%{!static-pie:" LD_DYNAMIC_OPTION "}}"
 # else
                            " -lunwind"
 # endif
@@ -1842,6 +1986,51 @@ init_spec (void)
 
   specs = sl;
 }
+
+/* Update the entry for SPEC in the static_specs table to point to VALUE,
+   ensuring that we free the previous value if necessary.  Set alloc_p for the
+   entry to ALLOC_P: this determines whether we take ownership of VALUE (i.e.
+   whether we need to free it later on).  */
+static void
+set_static_spec (const char **spec, const char *value, bool alloc_p)
+{
+  struct spec_list *sl = NULL;
+
+  for (unsigned i = 0; i < ARRAY_SIZE (static_specs); i++)
+    {
+      if (static_specs[i].ptr_spec == spec)
+       {
+         sl = static_specs + i;
+         break;
+       }
+    }
+
+  gcc_assert (sl);
+
+  if (sl->alloc_p)
+    {
+      const char *old = *spec;
+      free (const_cast <char *> (old));
+    }
+
+  *spec = value;
+  sl->alloc_p = alloc_p;
+}
+
+/* Update a static spec to a new string, taking ownership of that
+   string's memory.  */
+static void set_static_spec_owned (const char **spec, const char *val)
+{
+  return set_static_spec (spec, val, true);
+}
+
+/* Update a static spec to point to a new value, but don't take
+   ownership of (i.e. don't free) that string.  */
+static void set_static_spec_shared (const char **spec, const char *val)
+{
+  return set_static_spec (spec, val, false);
+}
+
 \f
 /* Change the value of spec NAME to SPEC.  If SPEC is empty, then the spec is
    removed; If the spec starts with a + then SPEC is added to the end of the
@@ -1910,15 +2099,23 @@ set_spec (const char *name, const char *spec, bool user_p)
 typedef const char *const_char_p; /* For DEF_VEC_P.  */
 
 /* Vector of pointers to arguments in the current line of specifications.  */
-
 static vec<const_char_p> argbuf;
 
+/* Likewise, but for the current @file.  */
+static vec<const_char_p> at_file_argbuf;
+
+/* Whether an @file is currently open.  */
+static bool in_at_file = false;
+
 /* Were the options -c, -S or -E passed.  */
 static int have_c = 0;
 
 /* Was the option -o passed.  */
 static int have_o = 0;
 
+/* Was the option -E passed.  */
+static int have_E = 0;
+
 /* Pointer to output file name passed in with -o. */
 static const char *output_file = 0;
 
@@ -1949,6 +2146,7 @@ static void
 alloc_args (void)
 {
   argbuf.create (10);
+  at_file_argbuf.create (10);
 }
 
 /* Clear out the vector of arguments (after a command is executed).  */
@@ -1957,6 +2155,7 @@ static void
 clear_args (void)
 {
   argbuf.truncate (0);
+  at_file_argbuf.truncate (0);
 }
 
 /* Add one argument to the vector at the end.
@@ -1969,7 +2168,10 @@ clear_args (void)
 static void
 store_arg (const char *arg, int delete_always, int delete_failure)
 {
-  argbuf.safe_push (arg);
+  if (in_at_file)
+    at_file_argbuf.safe_push (arg);
+  else
+    argbuf.safe_push (arg);
 
   if (delete_always || delete_failure)
     {
@@ -1982,6 +2184,67 @@ store_arg (const char *arg, int delete_always, int delete_failure)
       record_temp_file (arg, delete_always, delete_failure);
     }
 }
+
+/* Open a temporary @file into which subsequent arguments will be stored.  */
+
+static void
+open_at_file (void)
+{
+   if (in_at_file)
+     fatal_error (input_location, "cannot open nested response file");
+   else
+     in_at_file = true;
+}
+
+/* Close the temporary @file and add @file to the argument list.  */
+
+static void
+close_at_file (void)
+{
+  if (!in_at_file)
+    fatal_error (input_location, "cannot close nonexistent response file");
+
+  in_at_file = false;
+
+  const unsigned int n_args = at_file_argbuf.length ();
+  if (n_args == 0)
+    return;
+
+  char **argv = (char **) alloca (sizeof (char *) * (n_args + 1));
+  char *temp_file = make_temp_file ("");
+  char *at_argument = concat ("@", temp_file, NULL);
+  FILE *f = fopen (temp_file, "w");
+  int status;
+  unsigned int i;
+
+  /* Copy the strings over.  */
+  for (i = 0; i < n_args; i++)
+    argv[i] = CONST_CAST (char *, at_file_argbuf[i]);
+  argv[i] = NULL;
+
+  at_file_argbuf.truncate (0);
+
+  if (f == NULL)
+    fatal_error (input_location, "could not open temporary response file %s",
+                temp_file);
+
+  status = writeargv (argv, f);
+
+  if (status)
+    fatal_error (input_location,
+                "could not write to temporary response file %s",
+                temp_file);
+
+  status = fclose (f);
+
+  if (status == EOF)
+    fatal_error (input_location, "could not close temporary response file %s",
+                temp_file);
+
+  store_arg (at_argument, 0, 0);
+
+  record_temp_file (temp_file, !save_temps_flag, !save_temps_flag);
+}
 \f
 /* Load specs from a file name named FILENAME, replacing occurrences of
    various different types of line-endings, \r\n, \n\r and just \r, with
@@ -2004,15 +2267,20 @@ load_specs (const char *filename)
   /* Open and stat the file.  */
   desc = open (filename, O_RDONLY, 0);
   if (desc < 0)
-    pfatal_with_name (filename);
+    {
+    failed:
+      /* This leaves DESC open, but the OS will save us.  */
+      fatal_error (input_location, "cannot read spec file %qs: %m", filename);
+    }
+
   if (stat (filename, &statbuf) < 0)
-    pfatal_with_name (filename);
+    goto failed;
 
   /* Read contents of file into BUFFER.  */
   buffer = XNEWVEC (char, statbuf.st_size + 1);
   readlen = read (desc, buffer, (unsigned) statbuf.st_size);
   if (readlen < 0)
-    pfatal_with_name (filename);
+    goto failed;
   buffer[readlen] = 0;
   close (desc);
 
@@ -2393,7 +2661,7 @@ do                                                      \
     if (stat (NAME, &ST) >= 0 && S_ISREG (ST.st_mode))  \
       if (unlink (NAME) < 0)                            \
        if (VERBOSE_FLAG)                               \
-         perror_with_name (NAME);                      \
+         error ("%s: %m", (NAME));                     \
   } while (0)
 #endif
 
@@ -2873,6 +3141,44 @@ add_sysrooted_prefix (struct path_prefix *pprefix, const char *prefix,
   add_prefix (pprefix, prefix, component, priority,
              require_machine_suffix, os_multilib);
 }
+
+/* Same as add_prefix, but prepending target_sysroot_hdrs_suffix to prefix.  */
+
+static void
+add_sysrooted_hdrs_prefix (struct path_prefix *pprefix, const char *prefix,
+                          const char *component,
+                          /* enum prefix_priority */ int priority,
+                          int require_machine_suffix, int os_multilib)
+{
+  if (!IS_ABSOLUTE_PATH (prefix))
+    fatal_error (input_location, "system path %qs is not absolute", prefix);
+
+  if (target_system_root)
+    {
+      char *sysroot_no_trailing_dir_separator = xstrdup (target_system_root);
+      size_t sysroot_len = strlen (target_system_root);
+
+      if (sysroot_len > 0
+         && target_system_root[sysroot_len - 1] == DIR_SEPARATOR)
+       sysroot_no_trailing_dir_separator[sysroot_len - 1] = '\0';
+
+      if (target_sysroot_hdrs_suffix)
+       prefix = concat (sysroot_no_trailing_dir_separator,
+                        target_sysroot_hdrs_suffix, prefix, NULL);
+      else
+       prefix = concat (sysroot_no_trailing_dir_separator, prefix, NULL);
+
+      free (sysroot_no_trailing_dir_separator);
+
+      /* We have to override this because GCC's notion of sysroot
+        moves along with GCC.  */
+      component = "GCC";
+    }
+
+  add_prefix (pprefix, prefix, component, priority,
+             require_machine_suffix, os_multilib);
+}
+
 \f
 /* Execute the command specified by the arguments on the current line of spec.
    When using pipes, this includes several piped-together commands
@@ -2927,17 +3233,17 @@ execute (void)
   if (!wrapper_string)
     {
       string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, false);
-      commands[0].argv[0] = (string) ? string : commands[0].argv[0];
+      if (string)
+       commands[0].argv[0] = string;
     }
 
   for (n_commands = 1, i = 0; argbuf.iterate (i, &arg); i++)
     if (arg && strcmp (arg, "|") == 0)
       {                                /* each command.  */
 #if defined (__MSDOS__) || defined (OS2) || defined (VMS)
-       fatal_error (input_location, "-pipe not supported");
+       fatal_error (input_location, "%<-pipe%> not supported");
 #endif
-       argbuf[i] = 0; /* Termination of
-                                                    command args.  */
+       argbuf[i] = 0; /* Termination of command args.  */
        commands[n_commands].prog = argbuf[i + 1];
        commands[n_commands].argv
          = &(argbuf.address ())[i + 1];
@@ -3057,7 +3363,7 @@ execute (void)
                                   ? PEX_RECORD_TIMES : 0),
                  progname, temp_filename);
   if (pex == NULL)
-    fatal_error (input_location, "pex_init failed: %m");
+    fatal_error (input_location, "%<pex_init%> failed: %m");
 
   for (i = 0; i < n_commands; i++)
     {
@@ -3072,13 +3378,11 @@ execute (void)
                        NULL, NULL, &err);
       if (errmsg != NULL)
        {
-         if (err == 0)
-           fatal_error (input_location, errmsg);
-         else
-           {
-             errno = err;
-             pfatal_with_name (errmsg);
-           }
+         errno = err;
+         fatal_error (input_location,
+                      err ? G_("cannot execute %qs: %s: %m")
+                      : G_("cannot execute %qs: %s"),
+                      string, errmsg);
        }
 
       if (i && string != commands[i].prog)
@@ -3112,26 +3416,50 @@ execute (void)
        int status = statuses[i];
 
        if (WIFSIGNALED (status))
-         {
+         switch (WTERMSIG (status))
+           {
+           case SIGINT:
+           case SIGTERM:
+             /* SIGQUIT and SIGKILL are not available on MinGW.  */
+#ifdef SIGQUIT
+           case SIGQUIT:
+#endif
+#ifdef SIGKILL
+           case SIGKILL:
+#endif
+             /* The user (or environment) did something to the
+                inferior.  Making this an ICE confuses the user into
+                thinking there's a compiler bug.  Much more likely is
+                the user or OOM killer nuked it.  */
+             fatal_error (input_location,
+                          "%s signal terminated program %s",
+                          strsignal (WTERMSIG (status)),
+                          commands[i].prog);
+             break;
+
 #ifdef SIGPIPE
-           /* SIGPIPE is a special case.  It happens in -pipe mode
-              when the compiler dies before the preprocessor is done,
-              or the assembler dies before the compiler is done.
-              There's generally been an error already, and this is
-              just fallout.  So don't generate another error unless
-              we would otherwise have succeeded.  */
-           if (WTERMSIG (status) == SIGPIPE
-               && (signal_count || greatest_status >= MIN_FATAL_STATUS))
-             {
-               signal_count++;
-               ret_code = -1;
-             }
-           else
+           case SIGPIPE:
+             /* SIGPIPE is a special case.  It happens in -pipe mode
+                when the compiler dies before the preprocessor is
+                done, or the assembler dies before the compiler is
+                done.  There's generally been an error already, and
+                this is just fallout.  So don't generate another
+                error unless we would otherwise have succeeded.  */
+             if (signal_count || greatest_status >= MIN_FATAL_STATUS)
+               {
+                 signal_count++;
+                 ret_code = -1;
+                 break;
+               }
 #endif
-             internal_error_no_backtrace ("%s (program %s)",
+             /* FALLTHROUGH */
+
+           default:
+             /* The inferior failed to catch the signal.  */
+             internal_error_no_backtrace ("%s signal terminated program %s",
                                           strsignal (WTERMSIG (status)),
                                           commands[i].prog);
-         }
+           }
        else if (WIFEXITED (status)
                 && WEXITSTATUS (status) >= MIN_FATAL_STATUS)
          {
@@ -3353,7 +3681,7 @@ convert_filename (const char *name, int do_exe ATTRIBUTE_UNUSED,
 #if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
   /* If there is no filetype, make it the executable suffix (which includes
      the ".").  But don't get confused if we have just "-o".  */
-  if (! do_exe || TARGET_EXECUTABLE_SUFFIX[0] == 0 || (len == 2 && name[0] == '-'))
+  if (! do_exe || TARGET_EXECUTABLE_SUFFIX[0] == 0 || not_actual_file_p (name))
     return name;
 
   for (i = len - 1; i >= 0; i--)
@@ -3431,7 +3759,8 @@ display_help (void)
   fputs (_("  -S                       Compile only; do not assemble or link.\n"), stdout);
   fputs (_("  -c                       Compile and assemble, but do not link.\n"), stdout);
   fputs (_("  -o <file>                Place the output into <file>.\n"), stdout);
-  fputs (_("  -pie                     Create a position independent executable.\n"), stdout);
+  fputs (_("  -pie                     Create a dynamically linked position independent\n\
+                           executable.\n"), stdout);
   fputs (_("  -shared                  Create a shared library.\n"), stdout);
   fputs (_("\
   -x <language>            Specify the language of the following input files.\n\
@@ -3538,6 +3867,29 @@ save_switch (const char *opt, size_t n_args, const char *const *args,
   n_switches++;
 }
 
+/* Set the SOURCE_DATE_EPOCH environment variable to the current time if it is
+   not set already.  */
+
+static void
+set_source_date_epoch_envvar ()
+{
+  /* Array size is 21 = ceil(log_10(2^64)) + 1 to hold string representations
+     of 64 bit integers.  */
+  char source_date_epoch[21];
+  time_t tt;
+
+  errno = 0;
+  tt = time (NULL);
+  if (tt < (time_t) 0 || errno != 0)
+    tt = (time_t) 0;
+
+  snprintf (source_date_epoch, 21, "%llu", (unsigned long long) tt);
+  /* Using setenv instead of xputenv because we want the variable to remain
+     after finalizing so that it's still set in the second run when using
+     -fcompare-debug.  */
+  setenv ("SOURCE_DATE_EPOCH", source_date_epoch, 0);
+}
+
 /* Handle an option DECODED that is unknown to the option-processing
    machinery.  */
 
@@ -3582,7 +3934,7 @@ driver_wrong_lang_callback (const struct cl_decoded_option *decoded,
   const struct cl_option *option = &cl_options[decoded->opt_index];
 
   if (option->cl_reject_driver)
-    error ("unrecognized command line option %qs",
+    error ("unrecognized command-line option %qs",
           decoded->orig_option_with_args_text);
   else
     save_switch (decoded->canonical_option[0],
@@ -3699,7 +4051,8 @@ driver_handle_option (struct gcc_options *opts,
                      unsigned int lang_mask ATTRIBUTE_UNUSED, int kind,
                      location_t loc,
                      const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED,
-                     diagnostic_context *dc)
+                     diagnostic_context *dc,
+                     void (*) (void))
 {
   size_t opt_index = decoded->opt_index;
   const char *arg = decoded->arg;
@@ -3735,6 +4088,10 @@ driver_handle_option (struct gcc_options *opts,
       printf ("%s\n", spec_machine);
       exit (0);
 
+    case OPT_dumpfullversion:
+      printf ("%s\n", BASEVER);
+      exit (0);
+
     case OPT__version:
       print_version = 1;
 
@@ -3745,6 +4102,11 @@ driver_handle_option (struct gcc_options *opts,
       add_linker_option ("--version", strlen ("--version"));
       break;
 
+    case OPT__completion_:
+      validated = true;
+      completion = decoded->arg;
+      break;
+
     case OPT__help:
       print_help_list = 1;
 
@@ -3837,12 +4199,22 @@ driver_handle_option (struct gcc_options *opts,
       else
        compare_debug_opt = arg;
       save_switch (compare_debug_replacement_opt, 0, NULL, validated, true);
+      set_source_date_epoch_envvar ();
       return true;
 
     case OPT_fdiagnostics_color_:
       diagnostic_color_init (dc, value);
       break;
 
+    case OPT_fdiagnostics_urls_:
+      diagnostic_urls_init (dc, value);
+      break;
+
+    case OPT_fdiagnostics_format_:
+      diagnostic_output_format_init (dc,
+                                    (enum diagnostics_output_format)value);
+      break;
+
     case OPT_Wa_:
       {
        int prev, j;
@@ -3934,7 +4306,8 @@ driver_handle_option (struct gcc_options *opts,
       return true;
 
     case OPT_save_temps:
-      save_temps_flag = SAVE_TEMPS_CWD;
+      if (!save_temps_flag)
+       save_temps_flag = SAVE_TEMPS_DUMP;
       validated = true;
       break;
 
@@ -3945,8 +4318,25 @@ driver_handle_option (struct gcc_options *opts,
               || strcmp (arg, "object") == 0)
        save_temps_flag = SAVE_TEMPS_OBJ;
       else
-       fatal_error (input_location, "%qs is an unknown -save-temps option",
+       fatal_error (input_location, "%qs is an unknown %<-save-temps%> option",
                     decoded->orig_option_with_args_text);
+      save_temps_overrides_dumpdir = true;
+      break;
+
+    case OPT_dumpdir:
+      free (dumpdir);
+      dumpdir = xstrdup (arg);
+      save_temps_overrides_dumpdir = false;
+      break;
+
+    case OPT_dumpbase:
+      free (dumpbase);
+      dumpbase = xstrdup (arg);
+      break;
+
+    case OPT_dumpbase_ext:
+      free (dumpbase_ext);
+      dumpbase_ext = xstrdup (arg);
       break;
 
     case OPT_no_canonical_prefixes:
@@ -4031,6 +4421,10 @@ driver_handle_option (struct gcc_options *opts,
       validated = true;
       break;
 
+    case OPT_E:
+      have_E = true;
+      break;
+
     case OPT_x:
       spec_lang = arg;
       if (!strcmp (spec_lang, "none"))
@@ -4049,8 +4443,6 @@ driver_handle_option (struct gcc_options *opts,
       arg = convert_filename (arg, ! have_c, 0);
 #endif
       output_file = arg;
-      /* Save the output name in case -save-temps=obj was used.  */
-      save_temps_prefix = xstrdup (arg);
       /* On some systems, ld cannot handle "-o" without a space.  So
         split the option from its argument.  */
       save_switch ("-o", 1, &arg, validated, true);
@@ -4093,6 +4485,19 @@ driver_handle_option (struct gcc_options *opts,
   return true;
 }
 
+/* Return true if F2 is F1 followed by a single suffix, i.e., by a
+   period and additional characters other than a period.  */
+
+static inline bool
+adds_single_suffix_p (const char *f2, const char *f1)
+{
+  size_t len = strlen (f1);
+
+  return (strncmp (f1, f2, len) == 0
+         && f2[len] == '.'
+         && strchr (f2 + len + 1, '.') == NULL);
+}
+
 /* Put the driver's standard set of option handlers in *HANDLERS.  */
 
 static void
@@ -4109,6 +4514,32 @@ set_option_handlers (struct cl_option_handlers *handlers)
   handlers->handlers[2].mask = CL_TARGET;
 }
 
+
+/* Return the index into infiles for the single non-library
+   non-lto-wpa input file, -1 if there isn't any, or -2 if there is
+   more than one.  */
+static inline int
+single_input_file_index ()
+{
+  int ret = -1;
+
+  for (int i = 0; i < n_infiles; i++)
+    {
+      if (infiles[i].language
+         && (infiles[i].language[0] == '*'
+             || (flag_wpa
+                 && strcmp (infiles[i].language, "lto") == 0)))
+       continue;
+
+      if (ret != -1)
+       return -2;
+
+      ret = i;
+    }
+
+  return ret;
+}
+
 /* Create the vector `switches' and its contents.
    Store its length in `n_switches'.  */
 
@@ -4384,7 +4815,10 @@ process_command (unsigned int decoded_options_count,
            fname = xstrdup (arg);
 
           if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
-           perror_with_name (fname);
+           {
+             bool resp = fname[0] == '@' && access (fname + 1, F_OK) < 0;
+             error ("%s: %m", fname + resp);
+           }
           else
            add_infile (arg, spec_lang);
 
@@ -4415,51 +4849,413 @@ process_command (unsigned int decoded_options_count,
                       output_file);
     }
 
+  if (output_file != NULL && output_file[0] == '\0')
+    fatal_error (input_location, "output filename may not be empty");
+
+  /* -dumpdir and -save-temps=* both specify the location of aux/dump
+     outputs; the one that appears last prevails.  When compiling
+     multiple sources, an explicit dumpbase (minus -ext) may be
+     combined with an explicit or implicit dumpdir, whereas when
+     linking, a specified or implied link output name (minus
+     extension) may be combined with a prevailing -save-temps=* or an
+     otherwise implied dumpdir, but not override a prevailing
+     -dumpdir.  Primary outputs (e.g., linker output when linking
+     without -o, or .i, .s or .o outputs when processing multiple
+     inputs with -E, -S or -c, respectively) are NOT affected by these
+     -save-temps=/-dump* options, always landing in the current
+     directory and with the same basename as the input when an output
+     name is not given, but when they're intermediate outputs, they
+     are named like other aux outputs, so the options affect their
+     location and name.
+
+     Here are some examples.  There are several more in the
+     documentation of -o and -dump*, and some quite exhaustive tests
+     in gcc.misc-tests/outputs.exp.
+
+     When compiling any number of sources, no -dump* nor
+     -save-temps=*, all outputs in cwd without prefix:
+
+     # gcc -c b.c -gsplit-dwarf
+     -> cc1 [-dumpdir ./] -dumpbase b.c -dumpbase-ext .c # b.o b.dwo
+
+     # gcc -c b.c d.c -gsplit-dwarf
+     -> cc1 [-dumpdir ./] -dumpbase b.c -dumpbase-ext .c # b.o b.dwo
+     && cc1 [-dumpdir ./] -dumpbase d.c -dumpbase-ext .c # d.o d.dwo
+
+     When compiling and linking, no -dump* nor -save-temps=*, .o
+     outputs are temporary, aux outputs land in the dir of the output,
+     prefixed with the basename of the linker output:
+
+     # gcc b.c d.c -o ab -gsplit-dwarf
+     -> cc1 -dumpdir ab- -dumpbase b.c -dumpbase-ext .c # ab-b.dwo
+     && cc1 -dumpdir ab- -dumpbase d.c -dumpbase-ext .c # ab-d.dwo
+     && link ... -o ab
+
+     # gcc b.c d.c [-o a.out] -gsplit-dwarf
+     -> cc1 -dumpdir a- -dumpbase b.c -dumpbase-ext .c # a-b.dwo
+     && cc1 -dumpdir a- -dumpbase d.c -dumpbase-ext .c # a-d.dwo
+     && link ... [-o a.out]
+
+     When compiling and linking, a prevailing -dumpdir fully overrides
+     the prefix of aux outputs given by the output name:
+
+     # gcc -dumpdir f b.c d.c -gsplit-dwarf [-o [dir/]whatever]
+     -> cc1 -dumpdir f -dumpbase b.c -dumpbase-ext .c # fb.dwo
+     && cc1 -dumpdir f -dumpbase d.c -dumpbase-ext .c # fd.dwo
+     && link ... [-o whatever]
+
+     When compiling multiple inputs, an explicit -dumpbase is combined
+     with -dumpdir, affecting aux outputs, but not the .o outputs:
+
+     # gcc -dumpdir f -dumpbase g- b.c d.c -gsplit-dwarf -c
+     -> cc1 -dumpdir fg- -dumpbase b.c -dumpbase-ext .c # b.o fg-b.dwo
+     && cc1 -dumpdir fg- -dumpbase d.c -dumpbase-ext .c # d.o fg-d.dwo
+
+     When compiling and linking with -save-temps, the .o outputs that
+     would have been temporary become aux outputs, so they get
+     affected by -dump* flags:
+
+     # gcc -dumpdir f -dumpbase g- -save-temps b.c d.c
+     -> cc1 -dumpdir fg- -dumpbase b.c -dumpbase-ext .c # fg-b.o
+     && cc1 -dumpdir fg- -dumpbase d.c -dumpbase-ext .c # fg-d.o
+     && link
+
+     If -save-temps=* prevails over -dumpdir, however, the explicit
+     -dumpdir is discarded, as if it wasn't there.  The basename of
+     the implicit linker output, a.out or a.exe, becomes a- as the aux
+     output prefix for all compilations:
+
+     # gcc [-dumpdir f] -save-temps=cwd b.c d.c
+     -> cc1 -dumpdir a- -dumpbase b.c -dumpbase-ext .c # a-b.o
+     && cc1 -dumpdir a- -dumpbase d.c -dumpbase-ext .c # a-d.o
+     && link
+
+     A single -dumpbase, applying to multiple inputs, overrides the
+     linker output name, implied or explicit, as the aux output prefix:
+
+     # gcc [-dumpdir f] -dumpbase g- -save-temps=cwd b.c d.c
+     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
+     && cc1 -dumpdir g- -dumpbase d.c -dumpbase-ext .c # g-d.o
+     && link
+
+     # gcc [-dumpdir f] -dumpbase g- -save-temps=cwd b.c d.c -o dir/h.out
+     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
+     && cc1 -dumpdir g- -dumpbase d.c -dumpbase-ext .c # g-d.o
+     && link -o dir/h.out
+
+     Now, if the linker output is NOT overridden as a prefix, but
+     -save-temps=* overrides implicit or explicit -dumpdir, the
+     effective dump dir combines the dir selected by the -save-temps=*
+     option with the basename of the specified or implied link output:
+
+     # gcc [-dumpdir f] -save-temps=cwd b.c d.c -o dir/h.out
+     -> cc1 -dumpdir h- -dumpbase b.c -dumpbase-ext .c # h-b.o
+     && cc1 -dumpdir h- -dumpbase d.c -dumpbase-ext .c # h-d.o
+     && link -o dir/h.out
+
+     # gcc [-dumpdir f] -save-temps=obj b.c d.c -o dir/h.out
+     -> cc1 -dumpdir dir/h- -dumpbase b.c -dumpbase-ext .c # dir/h-b.o
+     && cc1 -dumpdir dir/h- -dumpbase d.c -dumpbase-ext .c # dir/h-d.o
+     && link -o dir/h.out
+
+     But then again, a single -dumpbase applying to multiple inputs
+     gets used instead of the linker output basename in the combined
+     dumpdir:
+
+     # gcc [-dumpdir f] -dumpbase g- -save-temps=obj b.c d.c -o dir/h.out
+     -> cc1 -dumpdir dir/g- -dumpbase b.c -dumpbase-ext .c # dir/g-b.o
+     && cc1 -dumpdir dir/g- -dumpbase d.c -dumpbase-ext .c # dir/g-d.o
+     && link -o dir/h.out
+
+     With a single input being compiled, the output basename does NOT
+     affect the dumpdir prefix.
+
+     # gcc -save-temps=obj b.c -gsplit-dwarf -c -o dir/b.o
+     -> cc1 -dumpdir dir/ -dumpbase b.c -dumpbase-ext .c # dir/b.o dir/b.dwo
+
+     but when compiling and linking even a single file, it does:
+
+     # gcc -save-temps=obj b.c -o dir/h.out
+     -> cc1 -dumpdir dir/h- -dumpbase b.c -dumpbase-ext .c # dir/h-b.o
+
+     unless an explicit -dumpdir prevails:
+
+     # gcc -save-temps[=obj] -dumpdir g- b.c -o dir/h.out
+     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
+
+  */
+
+  bool explicit_dumpdir = dumpdir;
+
+  if (!save_temps_overrides_dumpdir && explicit_dumpdir)
+    {
+      /* Do nothing.  */
+    }
+
   /* If -save-temps=obj and -o name, create the prefix to use for %b.
      Otherwise just make -save-temps=obj the same as -save-temps=cwd.  */
-  if (save_temps_flag == SAVE_TEMPS_OBJ && save_temps_prefix != NULL)
+  else if (save_temps_flag != SAVE_TEMPS_CWD && output_file != NULL)
     {
-      save_temps_length = strlen (save_temps_prefix);
-      temp = strrchr (lbasename (save_temps_prefix), '.');
-      if (temp)
-       {
-         save_temps_length -= strlen (temp);
-         save_temps_prefix[save_temps_length] = '\0';
-       }
-
+      free (dumpdir);
+      dumpdir = NULL;
+      temp = lbasename (output_file);
+      if (temp != output_file)
+       dumpdir = xstrndup (output_file,
+                           strlen (output_file) - strlen (temp));
     }
-  else if (save_temps_prefix != NULL)
+  else if (dumpdir)
     {
-      free (save_temps_prefix);
-      save_temps_prefix = NULL;
+      free (dumpdir);
+      dumpdir = NULL;
     }
 
-  if (save_temps_flag && use_pipes)
+  if (save_temps_flag)
+    save_temps_flag = SAVE_TEMPS_DUMP;
+
+  /* If there is any pathname component in an explicit -dumpbase, it
+     overrides dumpdir entirely, so discard it right away.  Although
+     the presence of an explicit -dumpdir matters for the driver, it
+     shouldn't matter for other processes, that get all that's needed
+     from the -dumpdir and -dumpbase always passed to them.  */
+  if (dumpdir && dumpbase && lbasename (dumpbase) != dumpbase)
     {
-      /* -save-temps overrides -pipe, so that temp files are produced */
-      if (save_temps_flag)
-       warning (0, "-pipe ignored because -save-temps specified");
-      use_pipes = 0;
+      free (dumpdir);
+      dumpdir = NULL;
     }
 
-  if (!compare_debug)
+  /* Check that dumpbase_ext matches the end of dumpbase, drop it
+     otherwise.  */
+  if (dumpbase_ext && dumpbase && *dumpbase)
     {
-      const char *gcd = env.get ("GCC_COMPARE_DEBUG");
+      int lendb = strlen (dumpbase);
+      int lendbx = strlen (dumpbase_ext);
 
-      if (gcd && gcd[0] == '-')
-       {
-         compare_debug = 2;
-         compare_debug_opt = gcd;
-       }
-      else if (gcd && *gcd && strcmp (gcd, "0"))
+      /* -dumpbase-ext must be a suffix proper; discard it if it
+         matches all of -dumpbase, as that would make for an empty
+         basename.  */
+      if (lendbx >= lendb
+         || strcmp (dumpbase + lendb - lendbx, dumpbase_ext) != 0)
        {
-         compare_debug = 3;
-         compare_debug_opt = "-gtoggle";
+         free (dumpbase_ext);
+         dumpbase_ext = NULL;
        }
     }
-  else if (compare_debug < 0)
+
+  /* -dumpbase with multiple sources goes into dumpdir.  With a single
+     source, it does only if linking and if dumpdir was not explicitly
+     specified.  */
+  if (dumpbase && *dumpbase
+      && (single_input_file_index () == -2
+         || (!have_c && !explicit_dumpdir)))
     {
-      compare_debug = 0;
+      char *prefix;
+
+      if (dumpbase_ext)
+       /* We checked that they match above.  */
+       dumpbase[strlen (dumpbase) - strlen (dumpbase_ext)] = '\0';
+
+      if (dumpdir)
+       prefix = concat (dumpdir, dumpbase, "-", NULL);
+      else
+       prefix = concat (dumpbase, "-", NULL);
+
+      free (dumpdir);
+      free (dumpbase);
+      free (dumpbase_ext);
+      dumpbase = dumpbase_ext = NULL;
+      dumpdir = prefix;
+      dumpdir_trailing_dash_added = true;
+    }
+
+  /* If dumpbase was not brought into dumpdir but we're linking, bring
+     output_file into dumpdir unless dumpdir was explicitly specified.
+     The test for !explicit_dumpdir is further below, because we want
+     to use the obase computation for a ghost outbase, passed to
+     GCC_COLLECT_OPTIONS.  */
+  else if (!have_c && (!explicit_dumpdir || (dumpbase && !*dumpbase)))
+    {
+      /* If we get here, we know dumpbase was not specified, or it was
+        specified as an empty string.  If it was anything else, it
+        would have combined with dumpdir above, because the condition
+        for dumpbase to be used when present is broader than the
+        condition that gets us here.  */
+      gcc_assert (!dumpbase || !*dumpbase);
+
+      const char *obase;
+      char *tofree = NULL;
+      if (!output_file || not_actual_file_p (output_file))
+       obase = "a";
+      else
+       {
+         obase = lbasename (output_file);
+         size_t blen = strlen (obase), xlen;
+         /* Drop the suffix if it's dumpbase_ext, if given,
+            otherwise .exe or the target executable suffix, or if the
+            output was explicitly named a.out, but not otherwise.  */
+         if (dumpbase_ext
+             ? (blen > (xlen = strlen (dumpbase_ext))
+                && strcmp ((temp = (obase + blen - xlen)),
+                           dumpbase_ext) == 0)
+             : ((temp = strrchr (obase + 1, '.'))
+                && (xlen = strlen (temp))
+                && (strcmp (temp, ".exe") == 0
+#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
+                    || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
+#endif
+                    || strcmp (obase, "a.out") == 0)))
+           {
+             tofree = xstrndup (obase, blen - xlen);
+             obase = tofree;
+           }
+       }
+
+      /* We wish to save this basename to the -dumpdir passed through
+        GCC_COLLECT_OPTIONS within maybe_run_linker, for e.g. LTO,
+        but we do NOT wish to add it to e.g. %b, so we keep
+        outbase_length as zero.  */
+      gcc_assert (!outbase);
+      outbase_length = 0;
+
+      /* If we're building [dir1/]foo[.exe] out of a single input
+        [dir2/]foo.c that shares the same basename, dump to
+        [dir2/]foo.c.* rather than duplicating the basename into
+        [dir2/]foo-foo.c.*.  */
+      int idxin;
+      if (dumpbase
+         || ((idxin = single_input_file_index ()) >= 0
+             && adds_single_suffix_p (lbasename (infiles[idxin].name),
+                                      obase)))
+       {
+         if (obase == tofree)
+           outbase = tofree;
+         else
+           {
+             outbase = xstrdup (obase);
+             free (tofree);
+           }
+         obase = tofree = NULL;
+       }
+      else
+       {
+         if (dumpdir)
+           {
+             char *p = concat (dumpdir, obase, "-", NULL);
+             free (dumpdir);
+             dumpdir = p;
+           }
+         else
+           dumpdir = concat (obase, "-", NULL);
+
+         dumpdir_trailing_dash_added = true;
+
+         free (tofree);
+         obase = tofree = NULL;
+       }
+
+      if (!explicit_dumpdir || dumpbase)
+       {
+         /* Absent -dumpbase and present -dumpbase-ext have been applied
+            to the linker output name, so compute fresh defaults for each
+            compilation.  */
+         free (dumpbase_ext);
+         dumpbase_ext = NULL;
+       }
+    }
+
+  /* Now, if we're compiling, or if we haven't used the dumpbase
+     above, then outbase (%B) is derived from dumpbase, if given, or
+     from the output name, given or implied.  We can't precompute
+     implied output names, but that's ok, since they're derived from
+     input names.  Just make sure we skip this if dumpbase is the
+     empty string: we want to use input names then, so don't set
+     outbase.  */
+  if ((dumpbase || have_c)
+      && !(dumpbase && !*dumpbase))
+    {
+      gcc_assert (!outbase);
+
+      if (dumpbase)
+       {
+         gcc_assert (single_input_file_index () != -2);
+         /* We do not want lbasename here; dumpbase with dirnames
+            overrides dumpdir entirely, even if dumpdir is
+            specified.  */
+         if (dumpbase_ext)
+           /* We've already checked above that the suffix matches.  */
+           outbase = xstrndup (dumpbase,
+                               strlen (dumpbase) - strlen (dumpbase_ext));
+         else
+           outbase = xstrdup (dumpbase);
+       }
+      else if (output_file && !not_actual_file_p (output_file))
+       {
+         outbase = xstrdup (lbasename (output_file));
+         char *p = strrchr (outbase + 1, '.');
+         if (p)
+           *p = '\0';
+       }
+
+      if (outbase)
+       outbase_length = strlen (outbase);
+    }
+
+  /* If there is any pathname component in an explicit -dumpbase, do
+     not use dumpdir, but retain it to pass it on to the compiler.  */
+  if (dumpdir)
+    dumpdir_length = strlen (dumpdir);
+  else
+    dumpdir_length = 0;
+
+  /* Check that dumpbase_ext, if still present, still matches the end
+     of dumpbase, if present, and drop it otherwise.  We only retained
+     it above when dumpbase was absent to maybe use it to drop the
+     extension from output_name before combining it with dumpdir.  We
+     won't deal with -dumpbase-ext when -dumpbase is not explicitly
+     given, even if just to activate backward-compatible dumpbase:
+     dropping it on the floor is correct, expected and documented
+     behavior.  Attempting to deal with a -dumpbase-ext that might
+     match the end of some input filename, or of the combination of
+     the output basename with the suffix of the input filename,
+     possible with an intermediate .gk extension for -fcompare-debug,
+     is just calling for trouble.  */
+  if (dumpbase_ext)
+    {
+      if (!dumpbase || !*dumpbase)
+       {
+         free (dumpbase_ext);
+         dumpbase_ext = NULL;
+       }
+      else
+       gcc_assert (strcmp (dumpbase + strlen (dumpbase)
+                           - strlen (dumpbase_ext), dumpbase_ext) == 0);
+    }
+
+  if (save_temps_flag && use_pipes)
+    {
+      /* -save-temps overrides -pipe, so that temp files are produced */
+      if (save_temps_flag)
+       warning (0, "%<-pipe%> ignored because %<-save-temps%> specified");
+      use_pipes = 0;
+    }
+
+  if (!compare_debug)
+    {
+      const char *gcd = env.get ("GCC_COMPARE_DEBUG");
+
+      if (gcd && gcd[0] == '-')
+       {
+         compare_debug = 2;
+         compare_debug_opt = gcd;
+       }
+      else if (gcd && *gcd && strcmp (gcd, "0"))
+       {
+         compare_debug = 3;
+         compare_debug_opt = "-gtoggle";
+       }
+    }
+  else if (compare_debug < 0)
+    {
+      compare_debug = 0;
       gcc_assert (!compare_debug_opt);
     }
 
@@ -4525,7 +5321,7 @@ process_command (unsigned int decoded_options_count,
   /* More prefixes are enabled in main, after we read the specs file
      and determine whether this is cross-compilation or not.  */
 
-  if (n_infiles == last_language_n_infiles && spec_lang != 0)
+  if (n_infiles != 0 && n_infiles == last_language_n_infiles && spec_lang != 0)
     warning (0, "%<-x %s%> after last input file has no effect", spec_lang);
 
   /* Synthesize -fcompare-debug flag from the GCC_COMPARE_DEBUG
@@ -4538,10 +5334,9 @@ process_command (unsigned int decoded_options_count,
     }
 
   /* Ensure we only invoke each subprocess once.  */
-  if (print_subprocess_help || print_help_list || print_version)
+  if (n_infiles == 0
+      && (print_subprocess_help || print_help_list || print_version))
     {
-      n_infiles = 0;
-
       /* Create a dummy input file, so that we can pass
         the help option on to the various sub-processes.  */
       add_infile ("help-dummy", "c");
@@ -4549,23 +5344,23 @@ process_command (unsigned int decoded_options_count,
 
   /* Decide if undefined variable references are allowed in specs.  */
 
-  /* --version and --help alone or together are safe.  Note that -v would
-     make them unsafe, as they'd then be run for subprocesses as well, the
-     location of which might depend on variables possibly coming from
-     self-specs.
-
-     Count the number of options we have for which undefined variables
-     are harmless for sure, and check that nothing else is set.  */
+  /* -v alone is safe. --version and --help alone or together are safe.  Note
+     that -v would make them unsafe, as they'd then be run for subprocesses as
+     well, the location of which might depend on variables possibly coming
+     from self-specs.  Note also that the command name is counted in
+     decoded_options_count.  */
 
-  unsigned n_varsafe_options = 0;
+  unsigned help_version_count = 0;
 
   if (print_version)
-    n_varsafe_options++;
-  
+    help_version_count++;
+
   if (print_help_list)
-    n_varsafe_options++;
-  
-  spec_undefvar_allowed = (n_varsafe_options == decoded_options_count - 1);
+    help_version_count++;
+
+  spec_undefvar_allowed =
+    ((verbose_flag && decoded_options_count == 2)
+     || help_version_count == decoded_options_count - 1);
 
   alloc_switch ();
   switches[n_switches].part1 = 0;
@@ -4628,6 +5423,28 @@ set_collect_gcc_options (void)
          obstack_grow (&collect_obstack, "'", 1);
        }
     }
+
+  if (dumpdir)
+    {
+      if (!first_time)
+       obstack_grow (&collect_obstack, " ", 1);
+      first_time = FALSE;
+
+      obstack_grow (&collect_obstack, "'-dumpdir' '", 12);
+      const char *p, *q;
+
+      q = dumpdir;
+      while ((p = strchr (q, '\'')))
+       {
+         obstack_grow (&collect_obstack, q, p - q);
+         obstack_grow (&collect_obstack, "'\\''", 4);
+         q = ++p;
+       }
+      obstack_grow (&collect_obstack, q, strlen (q));
+
+      obstack_grow (&collect_obstack, "'", 1);
+    }
+
   obstack_grow (&collect_obstack, "\0", 1);
   xputenv (XOBFINISH (&collect_obstack, char *));
 }
@@ -4743,7 +5560,7 @@ insert_wrapper (const char *wrapper)
     }
   while ((p = strchr (p, ',')) != NULL);
 
-  argbuf.safe_grow (old_length + n);
+  argbuf.safe_grow (old_length + n, true);
   memmove (argbuf.address () + n,
           argbuf.address (),
           old_length * sizeof (const_char_p));
@@ -4772,7 +5589,7 @@ do_spec (const char *spec)
 {
   int value;
 
-  value = do_spec_2 (spec);
+  value = do_spec_2 (spec, NULL);
 
   /* Force out any unfinished command.
      If -pipe, this forces out the last command if it ended in `|'.  */
@@ -4791,8 +5608,11 @@ do_spec (const char *spec)
   return value;
 }
 
+/* Process the spec SPEC, with SOFT_MATCHED_PART designating the current value
+   of a matched * pattern which may be re-injected by way of %*.  */
+
 static int
-do_spec_2 (const char *spec)
+do_spec_2 (const char *spec, const char *soft_matched_part)
 {
   int result;
 
@@ -4805,14 +5625,13 @@ do_spec_2 (const char *spec)
   input_from_pipe = 0;
   suffix_subst = NULL;
 
-  result = do_spec_1 (spec, 0, NULL);
+  result = do_spec_1 (spec, 0, soft_matched_part);
 
   end_going_arg ();
 
   return result;
 }
 
-
 /* Process the given spec string and add any new options to the end
    of the switches/n_switches array.  */
 
@@ -4870,7 +5689,7 @@ do_self_spec (const char *spec)
 {
   int i;
 
-  do_spec_2 (spec);
+  do_spec_2 (spec, NULL);
   do_spec_1 (" ", 0, NULL);
 
   /* Mark %<S switches processed by do_self_spec to be ignored permanently.
@@ -4998,39 +5817,6 @@ spec_path (char *path, void *data)
   return NULL;
 }
 
-/* Create a temporary FILE with the contents of ARGV. Add @FILE to the
-   argument list. */
-
-static void
-create_at_file (char **argv)
-{
-  char *temp_file = make_temp_file ("");
-  char *at_argument = concat ("@", temp_file, NULL);
-  FILE *f = fopen (temp_file, "w");
-  int status;
-
-  if (f == NULL)
-    fatal_error (input_location, "could not open temporary response file %s",
-                temp_file);
-
-  status = writeargv (argv, f);
-
-  if (status)
-    fatal_error (input_location,
-                "could not write to temporary response file %s",
-                temp_file);
-
-  status = fclose (f);
-
-  if (EOF == status)
-    fatal_error (input_location, "could not close temporary response file %s",
-                temp_file);
-
-  store_arg (at_argument, 0, 0);
-
-  record_temp_file (temp_file, !save_temps_flag, !save_temps_flag);
-}
-
 /* True if we should compile INFILE. */
 
 static bool
@@ -5058,6 +5844,34 @@ do_specs_vec (vec<char_p> vec)
     }
 }
 
+/* Add options passed via -Xassembler or -Wa to COLLECT_AS_OPTIONS.  */
+
+static void
+putenv_COLLECT_AS_OPTIONS (vec<char_p> vec)
+{
+  if (vec.is_empty ())
+     return;
+
+  obstack_init (&collect_obstack);
+  obstack_grow (&collect_obstack, "COLLECT_AS_OPTIONS=",
+               strlen ("COLLECT_AS_OPTIONS="));
+
+  char *opt;
+  unsigned ix;
+
+  FOR_EACH_VEC_ELT (vec, ix, opt)
+    {
+      obstack_1grow (&collect_obstack, '\'');
+      obstack_grow (&collect_obstack, opt, strlen (opt));
+      obstack_1grow (&collect_obstack, '\'');
+      if (ix < vec.length () - 1)
+       obstack_1grow(&collect_obstack, ' ');
+    }
+
+  obstack_1grow (&collect_obstack, '\0');
+  xputenv (XOBFINISH (&collect_obstack, char *));
+}
+
 /* Process the sub-spec SPEC as a portion of a larger spec.
    This is like processing a whole spec except that we do
    not initialize at the beginning and we do not supply a
@@ -5149,22 +5963,33 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
            fatal_error (input_location, "spec %qs invalid", spec);
 
          case 'b':
-           if (save_temps_length)
-             obstack_grow (&obstack, save_temps_prefix, save_temps_length);
-           else
+           /* Don't use %b in the linker command.  */
+           gcc_assert (suffixed_basename_length);
+           if (!this_is_output_file && dumpdir_length)
+             obstack_grow (&obstack, dumpdir, dumpdir_length);
+           if (this_is_output_file || !outbase_length)
              obstack_grow (&obstack, input_basename, basename_length);
+           else
+             obstack_grow (&obstack, outbase, outbase_length);
            if (compare_debug < 0)
              obstack_grow (&obstack, ".gk", 3);
            arg_going = 1;
            break;
 
          case 'B':
-           if (save_temps_length)
-             obstack_grow (&obstack, save_temps_prefix, save_temps_length);
+           /* Don't use %B in the linker command.  */
+           gcc_assert (suffixed_basename_length);
+           if (!this_is_output_file && dumpdir_length)
+             obstack_grow (&obstack, dumpdir, dumpdir_length);
+           if (this_is_output_file || !outbase_length)
+             obstack_grow (&obstack, input_basename, basename_length);
            else
-             obstack_grow (&obstack, input_basename, suffixed_basename_length);
+             obstack_grow (&obstack, outbase, outbase_length);
            if (compare_debug < 0)
              obstack_grow (&obstack, ".gk", 3);
+           obstack_grow (&obstack, input_basename + basename_length,
+                         suffixed_basename_length - basename_length);
+
            arg_going = 1;
            break;
 
@@ -5222,7 +6047,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;
-             inform (0, "%s", _(buf));
+             inform (UNKNOWN_LOCATION, "%s", _(buf));
              if (*p)
                p++;
            }
@@ -5317,42 +6142,44 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                    suffix_length += 3;
                  }
 
-               /* If -save-temps=obj and -o were specified, use that for the
+               /* If -save-temps was specified, use that for the
                   temp file.  */
-               if (save_temps_length)
-                 {
-                   char *tmp;
-                   temp_filename_length
-                     = save_temps_length + suffix_length + 1;
-                   tmp = (char *) alloca (temp_filename_length);
-                   memcpy (tmp, save_temps_prefix, save_temps_length);
-                   memcpy (tmp + save_temps_length, suffix, suffix_length);
-                   tmp[save_temps_length + suffix_length] = '\0';
-                   temp_filename = save_string (tmp, save_temps_length
-                                                     + suffix_length);
-                   obstack_grow (&obstack, temp_filename,
-                                 temp_filename_length);
-                   arg_going = 1;
-                   delete_this_arg = 0;
-                   break;
-                 }
-
-               /* 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.,
-                  gcc -save-temps foo.s would clobber foo.s with the
-                  output of cpp0).  So check for this condition and
-                  generate a temp file as the intermediate.  */
-
                if (save_temps_flag)
                  {
                    char *tmp;
-                   temp_filename_length = basename_length + suffix_length + 1;
+                   bool adjusted_suffix = false;
+                   if (suffix_length
+                       && !outbase_length && !basename_length
+                       && !dumpdir_trailing_dash_added)
+                     {
+                       adjusted_suffix = true;
+                       suffix++;
+                       suffix_length--;
+                     }
+                   temp_filename_length
+                     = dumpdir_length + suffix_length + 1;
+                   if (outbase_length)
+                     temp_filename_length += outbase_length;
+                   else
+                     temp_filename_length += basename_length;
                    tmp = (char *) alloca (temp_filename_length);
-                   memcpy (tmp, input_basename, basename_length);
-                   memcpy (tmp + basename_length, suffix, suffix_length);
-                   tmp[basename_length + suffix_length] = '\0';
+                   if (dumpdir_length)
+                     memcpy (tmp, dumpdir, dumpdir_length);
+                   if (outbase_length)
+                     memcpy (tmp + dumpdir_length, outbase,
+                             outbase_length);
+                   else if (basename_length)
+                     memcpy (tmp + dumpdir_length, input_basename,
+                             basename_length);
+                   memcpy (tmp + temp_filename_length - suffix_length - 1,
+                           suffix, suffix_length);
+                   if (adjusted_suffix)
+                     {
+                       adjusted_suffix = false;
+                       suffix--;
+                       suffix_length++;
+                     }
+                   tmp[temp_filename_length - 1] = '\0';
                    temp_filename = tmp;
 
                    if (filename_cmp (temp_filename, gcc_input_filename) != 0)
@@ -5387,8 +6214,9 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                        if (files_differ)
 #endif
                          {
-                           temp_filename = save_string (temp_filename,
-                                                        temp_filename_length + 1);
+                           temp_filename
+                             = save_string (temp_filename,
+                                            temp_filename_length - 1);
                            obstack_grow (&obstack, temp_filename,
                                                    temp_filename_length);
                            arg_going = 1;
@@ -5442,41 +6270,22 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
          case 'i':
            if (combine_inputs)
              {
+               /* We are going to expand `%i' into `@FILE', where FILE
+                  is a newly-created temporary filename.  The filenames
+                  that would usually be expanded in place of %o will be
+                  written to the temporary file.  */
                if (at_file_supplied)
-                 {
-                   /* We are going to expand `%i' to `@FILE', where FILE
-                      is a newly-created temporary filename.  The filenames
-                      that would usually be expanded in place of %o will be
-                      written to the temporary file.  */
-                   char **argv;
-                   int n_files = 0;
-                   int j;
-
-                   for (i = 0; i < n_infiles; i++)
-                     if (compile_input_file_p (&infiles[i]))
-                       n_files++;
-
-                   argv = (char **) alloca (sizeof (char *) * (n_files + 1));
-
-                   /* Copy the strings over.  */
-                   for (i = 0, j = 0; i < n_infiles; i++)
-                     if (compile_input_file_p (&infiles[i]))
-                       {
-                         argv[j] = CONST_CAST (char *, infiles[i].name);
-                         infiles[i].compiled = true;
-                         j++;
-                       }
-                   argv[j] = NULL;
+                 open_at_file ();
 
-                   create_at_file (argv);
-                 }
-               else
-                 for (i = 0; (int) i < n_infiles; i++)
-                   if (compile_input_file_p (&infiles[i]))
-                     {
-                       store_arg (infiles[i].name, 0, 0);
-                       infiles[i].compiled = true;
-                     }
+               for (i = 0; (int) i < n_infiles; i++)
+                 if (compile_input_file_p (&infiles[i]))
+                   {
+                     store_arg (infiles[i].name, 0, 0);
+                     infiles[i].compiled = true;
+                   }
+
+               if (at_file_supplied)
+                 close_at_file ();
              }
            else
              {
@@ -5549,45 +6358,20 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
            break;
 
          case 'o':
-           {
-             int max = n_infiles;
-             max += lang_specific_extra_outfiles;
-
-              if (HAVE_GNU_LD && at_file_supplied)
-                {
-                  /* We are going to expand `%o' to `@FILE', where FILE
-                     is a newly-created temporary filename.  The filenames
-                     that would usually be expanded in place of %o will be
-                     written to the temporary file.  */
-
-                  char **argv;
-                  int n_files, j;
-
-                  /* Convert OUTFILES into a form suitable for writeargv.  */
-
-                  /* Determine how many are non-NULL.  */
-                  for (n_files = 0, i = 0; i < max; i++)
-                    n_files += outfiles[i] != NULL;
-
-                  argv = (char **) alloca (sizeof (char *) * (n_files + 1));
-
-                  /* Copy the strings over.  */
-                  for (i = 0, j = 0; i < max; i++)
-                    if (outfiles[i])
-                      {
-                        argv[j] = CONST_CAST (char *, outfiles[i]);
-                        j++;
-                      }
-                  argv[j] = NULL;
-
-                 create_at_file (argv);
-                }
-              else
-                for (i = 0; i < max; i++)
-                 if (outfiles[i])
-                   store_arg (outfiles[i], 0, 0);
-             break;
-           }
+           /* We are going to expand `%o' into `@FILE', where FILE
+              is a newly-created temporary filename.  The filenames
+              that would usually be expanded in place of %o will be
+              written to the temporary file.  */
+           if (at_file_supplied)
+             open_at_file ();
+
+           for (i = 0; i < n_infiles + lang_specific_extra_outfiles; i++)
+             if (outfiles[i])
+               store_arg (outfiles[i], 0, 0);
+
+           if (at_file_supplied)
+             close_at_file ();
+           break;
 
          case 'O':
            obstack_grow (&obstack, TARGET_OBJECT_SUFFIX, strlen (TARGET_OBJECT_SUFFIX));
@@ -5628,6 +6412,20 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
              break;
            }
 
+         case '@':
+           /* Handle the {...} following the %@.  */
+           if (*p != '{')
+             fatal_error (input_location,
+                          "spec %qs has invalid %<%%@%c%>", spec, *p);
+           if (at_file_supplied)
+             open_at_file ();
+           p = handle_braces (p + 1);
+           if (at_file_supplied)
+             close_at_file ();
+           if (p == 0)
+             return -1;
+           break;
+
          /* %x{OPTION} records OPTION for %X to output.  */
          case 'x':
            {
@@ -5772,7 +6570,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
            break;
 
          case ':':
-           p = handle_spec_function (p, NULL);
+           p = handle_spec_function (p, NULL, soft_matched_part);
            if (p == 0)
              return -1;
            break;
@@ -5892,6 +6690,14 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
            }
            break;
 
+         case '"':
+           /* End a previous argument, if there is one, then issue an
+              empty argument.  */
+           end_going_arg ();
+           arg_going = 1;
+           end_going_arg ();
+           break;
+
          default:
            error ("spec failure: unrecognized spec option %qc", c);
            break;
@@ -5902,6 +6708,9 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
        /* Backslash: treat next character as ordinary.  */
        c = *p++;
 
+       /* When adding more cases that previously matched default, make
+          sure to adjust quote_spec_char_p as well.  */
+
        /* Fall through.  */
       default:
        /* Ordinary character: put it into the current argument.  */
@@ -5934,7 +6743,8 @@ lookup_spec_function (const char *name)
 /* Evaluate a spec function.  */
 
 static const char *
-eval_spec_function (const char *func, const char *args)
+eval_spec_function (const char *func, const char *args,
+                   const char *soft_matched_part)
 {
   const struct spec_function *sf;
   const char *funcval;
@@ -5984,8 +6794,9 @@ eval_spec_function (const char *func, const char *args)
      arguments.  */
 
   alloc_args ();
-  if (do_spec_2 (args) < 0)
-    fatal_error (input_location, "error in args to spec function %qs", func);
+  if (do_spec_2 (args, soft_matched_part) < 0)
+    fatal_error (input_location, "error in arguments 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.  */
@@ -6021,10 +6832,14 @@ eval_spec_function (const char *func, const char *args)
    NULL if no processing is required.
 
    If RETVAL_NONNULL is not NULL, then store a bool whether function
-   returned non-NULL.  */
+   returned non-NULL.
+
+   SOFT_MATCHED_PART holds the current value of a matched * pattern, which
+   may be re-expanded with a %* as part of the function arguments.  */
 
 static const char *
-handle_spec_function (const char *p, bool *retval_nonnull)
+handle_spec_function (const char *p, bool *retval_nonnull,
+                     const char *soft_matched_part)
 {
   char *func, *args;
   const char *endp, *funcval;
@@ -6067,7 +6882,7 @@ handle_spec_function (const char *p, bool *retval_nonnull)
 
   /* p now points to just past the end of the spec function expression.  */
 
-  funcval = eval_spec_function (func, args);
+  funcval = eval_spec_function (func, args, soft_matched_part);
   if (funcval != NULL && do_spec_1 (funcval, 0, NULL) < 0)
     p = NULL;
   if (retval_nonnull)
@@ -6179,6 +6994,8 @@ handle_braces (const char *p)
 {
   const char *atom, *end_atom;
   const char *d_atom = NULL, *d_end_atom = NULL;
+  char *esc_buf = NULL, *d_esc_buf = NULL;
+  int esc;
   const char *orig = p;
 
   bool a_is_suffix;
@@ -6219,7 +7036,7 @@ handle_braces (const char *p)
        {
          atom = NULL;
          end_atom = NULL;
-         p = handle_spec_function (p + 2, &a_matched);
+         p = handle_spec_function (p + 2, &a_matched, NULL);
        }
       else
        {
@@ -6229,11 +7046,42 @@ handle_braces (const char *p)
            p++, a_is_spectype = true;
 
          atom = p;
+         esc = 0;
          while (ISIDNUM (*p) || *p == '-' || *p == '+' || *p == '='
-                || *p == ',' || *p == '.' || *p == '@')
-           p++;
+                || *p == ',' || *p == '.' || *p == '@' || *p == '\\')
+           {
+             if (*p == '\\')
+               {
+                 p++;
+                 if (!*p)
+                   fatal_error (input_location,
+                                "braced spec %qs ends in escape", orig);
+                 esc++;
+               }
+             p++;
+           }
          end_atom = p;
 
+         if (esc)
+           {
+             const char *ap;
+             char *ep;
+
+             if (esc_buf && esc_buf != d_esc_buf)
+               free (esc_buf);
+             esc_buf = NULL;
+             ep = esc_buf = (char *) xmalloc (end_atom - atom - esc + 1);
+             for (ap = atom; ap != end_atom; ap++, ep++)
+               {
+                 if (*ap == '\\')
+                   ap++;
+                 *ep = *ap;
+               }
+             *ep = '\0';
+             atom = esc_buf;
+             end_atom = ep;
+           }
+
          if (*p == '*')
            p++, a_is_starred = 1;
        }
@@ -6300,6 +7148,7 @@ handle_braces (const char *p)
                      disj_matched = true;
                      d_atom = atom;
                      d_end_atom = end_atom;
+                     d_esc_buf = esc_buf;
                    }
                }
            }
@@ -6311,7 +7160,7 @@ handle_braces (const char *p)
              p = process_brace_body (p + 1, d_atom, d_end_atom, disj_starred,
                                      disj_matched && !n_way_matched);
              if (p == 0)
-               return 0;
+               goto done;
 
              /* If we have an N-way choice, reset state for the next
                 disjunction.  */
@@ -6332,6 +7181,12 @@ handle_braces (const char *p)
     }
   while (*p++ != '}');
 
+ done:
+  if (d_esc_buf && d_esc_buf != esc_buf)
+    free (d_esc_buf);
+  if (esc_buf)
+    free (esc_buf);
+
   return p;
 
  invalid:
@@ -6593,6 +7448,11 @@ print_configuration (FILE *file)
 #endif
 
   fnotice (file, "Thread model: %s\n", thrmod);
+  fnotice (file, "Supported LTO compression algorithms: zlib");
+#ifdef HAVE_ZSTD_H
+  fnotice (file, " zstd");
+#endif
+  fnotice (file, "\n");
 
   /* compiler_version is truncated at the first space when initialized
   from version string, so truncate version_string at the first space
@@ -6726,20 +7586,18 @@ run_attempt (const char **new_argv, const char *out_temp,
 
   pex = pex_init (PEX_USE_PIPES, new_argv[0], NULL);
   if (!pex)
-    fatal_error (input_location, "pex_init failed: %m");
+    fatal_error (input_location, "%<pex_init%> failed: %m");
 
   errmsg = pex_run (pex, pex_flags, new_argv[0],
-                   CONST_CAST2 (char *const *, const char **, &new_argv[1]), out_temp,
-                   err_temp, &err);
+                   CONST_CAST2 (char *const *, const char **, &new_argv[1]),
+                   out_temp, err_temp, &err);
   if (errmsg != NULL)
     {
-      if (err == 0)
-       fatal_error (input_location, errmsg);
-      else
-       {
-         errno = err;
-         pfatal_with_name (errmsg);
-       }
+      errno = err;
+      fatal_error (input_location,
+                  err ? G_ ("cannot execute %qs: %s: %m")
+                  : G_ ("cannot execute %qs: %s"),
+                  new_argv[0], errmsg);
     }
 
   if (!pex_get_status (pex, 1, &exit_status))
@@ -6908,8 +7766,8 @@ try_generate_repro (const char **argv)
 
     /* In final attempt we append compiler options and preprocesssed code to last
        generated .out file with configuration and backtrace.  */
-    char **output = &temp_stdout_files[RETRY_ICE_ATTEMPTS - 1];
-    do_report_bug (new_argv, nargs, stderr_commented, output);
+    char **err = &temp_stderr_files[RETRY_ICE_ATTEMPTS - 1];
+    do_report_bug (new_argv, nargs, stderr_commented, err);
   }
 
 out:
@@ -7047,7 +7905,7 @@ compare_files (char *cmpfile[])
 
     if (!ret && length[0] != length[1])
       {
-       error ("%s: -fcompare-debug failure (length)", gcc_input_filename);
+       error ("%s: %<-fcompare-debug%> failure (length)", gcc_input_filename);
        ret = 1;
       }
 
@@ -7077,7 +7935,7 @@ compare_files (char *cmpfile[])
       {
        if (memcmp (map[0], map[1], length[0]) != 0)
          {
-           error ("%s: -fcompare-debug failure", gcc_input_filename);
+           error ("%s: %<-fcompare-debug%> failure", gcc_input_filename);
            ret = 1;
          }
       }
@@ -7114,7 +7972,7 @@ compare_files (char *cmpfile[])
 
        if (c0 != c1)
          {
-           error ("%s: -fcompare-debug failure",
+           error ("%s: %<-fcompare-debug%> failure",
                   gcc_input_filename);
            ret = 1;
            break;
@@ -7135,8 +7993,7 @@ compare_files (char *cmpfile[])
 
 driver::driver (bool can_finalize, bool debug) :
   explicit_link_files (NULL),
-  decoded_options (NULL),
-  m_option_suggestions (NULL)
+  decoded_options (NULL)
 {
   env.init (can_finalize, debug);
 }
@@ -7145,14 +8002,6 @@ driver::~driver ()
 {
   XDELETEVEC (explicit_link_files);
   XDELETEVEC (decoded_options);
-  if (m_option_suggestions)
-    {
-      int i;
-      char *str;
-      FOR_EACH_VEC_ELT (*m_option_suggestions, i, str)
-       free (str);
-      delete m_option_suggestions;
-    }
 }
 
 /* driver::main is implemented as a series of driver:: method calls.  */
@@ -7168,11 +8017,18 @@ driver::main (int argc, char **argv)
   global_initializations ();
   build_multilib_strings ();
   set_up_specs ();
+  putenv_COLLECT_AS_OPTIONS (assembler_options);
   putenv_COLLECT_GCC (argv[0]);
   maybe_putenv_COLLECT_LTO_WRAPPER ();
   maybe_putenv_OFFLOAD_TARGETS ();
   handle_unrecognized_options ();
 
+  if (completion)
+    {
+      m_option_proposer.suggest_completion (completion);
+      return 0;
+    }
+
   if (!maybe_print_and_exit ())
     return 0;
 
@@ -7221,10 +8077,6 @@ driver::expand_at_files (int *argc, char ***argv) const
 void
 driver::decode_argv (int argc, const char **argv)
 {
-  /* Register the language-independent parameters.  */
-  global_init_params ();
-  finish_params ();
-
   init_opts_obstack ();
   init_options_struct (&global_options, &global_options_set);
 
@@ -7245,6 +8097,7 @@ driver::global_initializations ()
 
   diagnostic_initialize (global_dc, 0);
   diagnostic_color_init (global_dc);
+  diagnostic_urls_init (global_dc);
 
 #ifdef GCC_DRIVER_HOST_INITIALIZATION
   /* Perform host dependent initialization when needed.  */
@@ -7419,10 +8272,11 @@ driver::set_up_specs () const
   /* Process sysroot_suffix_spec.  */
   if (*sysroot_suffix_spec != 0
       && !no_sysroot_suffix
-      && do_spec_2 (sysroot_suffix_spec) == 0)
+      && do_spec_2 (sysroot_suffix_spec, NULL) == 0)
     {
       if (argbuf.length () > 1)
-        error ("spec failure: more than one arg to SYSROOT_SUFFIX_SPEC");
+       error ("spec failure: more than one argument to "
+              "%<SYSROOT_SUFFIX_SPEC%>");
       else if (argbuf.length () == 1)
         target_sysroot_suffix = xstrdup (argbuf.last ());
     }
@@ -7443,17 +8297,18 @@ driver::set_up_specs () const
   /* Process sysroot_hdrs_suffix_spec.  */
   if (*sysroot_hdrs_suffix_spec != 0
       && !no_sysroot_suffix
-      && do_spec_2 (sysroot_hdrs_suffix_spec) == 0)
+      && do_spec_2 (sysroot_hdrs_suffix_spec, NULL) == 0)
     {
       if (argbuf.length () > 1)
-        error ("spec failure: more than one arg to SYSROOT_HEADERS_SUFFIX_SPEC");
+       error ("spec failure: more than one argument "
+              "to %<SYSROOT_HEADERS_SUFFIX_SPEC%>");
       else if (argbuf.length () == 1)
         target_sysroot_hdrs_suffix = xstrdup (argbuf.last ());
     }
 
   /* Look for startfiles in the standard places.  */
   if (*startfile_prefix_spec != 0
-      && do_spec_2 (startfile_prefix_spec) == 0
+      && do_spec_2 (startfile_prefix_spec, NULL) == 0
       && do_spec_1 (" ", 0, NULL) == 0)
     {
       const char *arg;
@@ -7612,7 +8467,7 @@ driver::maybe_putenv_COLLECT_LTO_WRAPPER () const
   if (lto_wrapper_file)
     {
       lto_wrapper_file = convert_white_space (lto_wrapper_file);
-      lto_wrapper_spec = lto_wrapper_file;
+      set_static_spec_owned (&lto_wrapper_spec, lto_wrapper_file);
       obstack_init (&collect_obstack);
       obstack_grow (&collect_obstack, "COLLECT_LTO_WRAPPER=",
                    sizeof ("COLLECT_LTO_WRAPPER=") - 1);
@@ -7641,92 +8496,6 @@ driver::maybe_putenv_OFFLOAD_TARGETS () const
   offload_targets = NULL;
 }
 
-/* Helper function for driver::suggest_option.  Populate
-   m_option_suggestions with candidate strings for misspelled options.
-   The strings will be freed by the driver's dtor.  */
-
-void
-driver::build_option_suggestions (void)
-{
-  gcc_assert (m_option_suggestions == NULL);
-  m_option_suggestions = new auto_vec <char *> ();
-
-  /* We build a vec of m_option_suggestions, using add_misspelling_candidates
-     to add copies of strings, without a leading dash.  */
-
-  for (unsigned int i = 0; i < cl_options_count; i++)
-    {
-      const struct cl_option *option = &cl_options[i];
-      const char *opt_text = option->opt_text;
-      switch (i)
-       {
-       default:
-         if (option->var_type == CLVC_ENUM)
-           {
-             const struct cl_enum *e = &cl_enums[option->var_enum];
-             for (unsigned j = 0; e->values[j].arg != NULL; j++)
-               {
-                 char *with_arg = concat (opt_text, e->values[j].arg, NULL);
-                 add_misspelling_candidates (m_option_suggestions, with_arg);
-                 free (with_arg);
-               }
-           }
-         else
-           add_misspelling_candidates (m_option_suggestions, opt_text);
-         break;
-
-       case OPT_fsanitize_:
-       case OPT_fsanitize_recover_:
-         /* -fsanitize= and -fsanitize-recover= can take
-            a comma-separated list of arguments.  Given that combinations
-            are supported, we can't add all potential candidates to the
-            vec, but if we at least add them individually without commas,
-            we should do a better job e.g. correcting
-              "-sanitize=address"
-            to
-              "-fsanitize=address"
-            rather than to "-Wframe-address" (PR driver/69265).  */
-         {
-           for (int j = 0; sanitizer_opts[j].name != NULL; ++j)
-             {
-               /* Get one arg at a time e.g. "-fsanitize=address".  */
-               char *with_arg = concat (opt_text,
-                                        sanitizer_opts[j].name,
-                                        NULL);
-               /* Add with_arg and all of its variant spellings e.g.
-                  "-fno-sanitize=address" to candidates (albeit without
-                  leading dashes).  */
-               add_misspelling_candidates (m_option_suggestions, with_arg);
-               free (with_arg);
-             }
-         }
-         break;
-       }
-    }
-}
-
-/* Helper function for driver::handle_unrecognized_options.
-
-   Given an unrecognized option BAD_OPT (without the leading dash),
-   locate the closest reasonable matching option (again, without the
-   leading dash), or NULL.
-
-   The returned string is owned by the driver instance.  */
-
-const char *
-driver::suggest_option (const char *bad_opt)
-{
-  /* Lazily populate m_option_suggestions.  */
-  if (!m_option_suggestions)
-    build_option_suggestions ();
-  gcc_assert (m_option_suggestions);
-
-  /* "m_option_suggestions" is now populated.  Use it.  */
-  return find_closest_string
-    (bad_opt,
-     (auto_vec <const char *> *) m_option_suggestions);
-}
-
 /* Reject switches that no pass was interested in.  */
 
 void
@@ -7735,13 +8504,13 @@ driver::handle_unrecognized_options ()
   for (size_t i = 0; (int) i < n_switches; i++)
     if (! switches[i].validated)
       {
-       const char *hint = suggest_option (switches[i].part1);
+       const char *hint = m_option_proposer.suggest_option (switches[i].part1);
        if (hint)
-         error ("unrecognized command line option %<-%s%>;"
+         error ("unrecognized command-line option %<-%s%>;"
                 " did you mean %<-%s%>?",
                 switches[i].part1, hint);
        else
-         error ("unrecognized command line option %<-%s%>",
+         error ("unrecognized command-line option %<-%s%>",
                 switches[i].part1);
       }
 }
@@ -7894,7 +8663,7 @@ driver::maybe_print_and_exit () const
     {
       printf (_("%s %s%s\n"), progname, pkgversion_string,
              version_string);
-      printf ("Copyright %s 2016 Free Software Foundation, Inc.\n",
+      printf ("Copyright %s 2021 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"),
@@ -7979,7 +8748,8 @@ driver::prepare_infiles ()
 
   if (!combine_inputs && have_c && have_o && lang_n_infiles > 1)
     fatal_error (input_location,
-                "cannot specify -o with -c, -S or -E with multiple files");
+                "cannot specify %<-o%> with %<-c%>, %<-S%> or %<-E%> "
+                "with multiple files");
 
   /* No early exit needed from main; we can continue.  */
   return false;
@@ -8044,7 +8814,8 @@ driver::do_spec_on_infiles () const
              else if (compare_debug && debug_check_temp_file[0])
                {
                  if (verbose_flag)
-                   inform (0, "recompiling with -fcompare-debug");
+                   inform (UNKNOWN_LOCATION,
+                           "recompiling with %<-fcompare-debug%>");
 
                  compare_debug = -compare_debug;
                  n_switches = n_switches_debug_check[1];
@@ -8060,7 +8831,7 @@ driver::do_spec_on_infiles () const
 
                  if (value < 0)
                    {
-                     error ("during -fcompare-debug recompilation");
+                     error ("during %<-fcompare-debug%> recompilation");
                      this_file_error = 1;
                    }
 
@@ -8069,7 +8840,7 @@ driver::do_spec_on_infiles () const
                                               debug_check_temp_file[1]));
 
                  if (verbose_flag)
-                   inform (0, "comparing final insns dumps");
+                   inform (UNKNOWN_LOCATION, "comparing final insns dumps");
 
                  if (compare_files (debug_check_temp_file))
                    this_file_error = 1;
@@ -8146,12 +8917,48 @@ driver::maybe_run_linker (const char *argv0) const
     if (explicit_link_files[i] || outfiles[i] != NULL)
       num_linker_inputs++;
 
+  /* Arrange for temporary file names created during linking to take
+     on names related with the linker output rather than with the
+     inputs when appropriate.  */
+  if (outbase && *outbase)
+    {
+      if (dumpdir)
+       {
+         char *tofree = dumpdir;
+         gcc_checking_assert (strlen (dumpdir) == dumpdir_length);
+         dumpdir = concat (dumpdir, outbase, ".", NULL);
+         free (tofree);
+       }
+      else
+       dumpdir = concat (outbase, ".", NULL);
+      dumpdir_length += strlen (outbase) + 1;
+      dumpdir_trailing_dash_added = true;
+    }
+  else if (dumpdir_trailing_dash_added)
+    {
+      gcc_assert (dumpdir[dumpdir_length - 1] == '-');
+      dumpdir[dumpdir_length - 1] = '.';
+    }
+
+  if (dumpdir_trailing_dash_added)
+    {
+      gcc_assert (dumpdir_length > 0);
+      gcc_assert (dumpdir[dumpdir_length - 1] == '.');
+      dumpdir_length--;
+    }
+
+  free (outbase);
+  input_basename = outbase = NULL;
+  outbase_length = suffixed_basename_length = basename_length = 0;
+
   /* Run ld to link all the compiler output files.  */
 
   if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2)
     {
       int tmp = execution_count;
 
+      detect_jobserver ();
+
       if (! have_c)
        {
 #if HAVE_LTO_PLUGIN > 0
@@ -8167,7 +8974,7 @@ driver::maybe_run_linker (const char *argv0) const
            {
              char *s = find_a_file (&exec_prefixes, "collect2", X_OK, false);
              if (s == NULL)
-               linker_name_spec = "ld";
+               set_static_spec_shared (&linker_name_spec, "ld");
            }
 
 #if HAVE_LTO_PLUGIN > 0
@@ -8186,12 +8993,12 @@ driver::maybe_run_linker (const char *argv0) const
                                             false);
              if (!temp_spec)
                fatal_error (input_location,
-                            "-fuse-linker-plugin, but %s not found",
+                            "%<-fuse-linker-plugin%>, but %s not found",
                             LTOPLUGINSONAME);
              linker_plugin_file_spec = convert_white_space (temp_spec);
            }
 #endif
-         lto_gcc_spec = argv0;
+         set_static_spec_shared (&lto_gcc_spec, argv0);
        }
 
       /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
@@ -8241,6 +9048,46 @@ driver::final_actions () const
     }
 }
 
+/* Detect whether jobserver is active and working.  If not drop
+   --jobserver-auth from MAKEFLAGS.  */
+
+void
+driver::detect_jobserver () const
+{
+  /* Detect jobserver and drop it if it's not working.  */
+  const char *makeflags = env.get ("MAKEFLAGS");
+  if (makeflags != NULL)
+    {
+      const char *needle = "--jobserver-auth=";
+      const char *n = strstr (makeflags, needle);
+      if (n != NULL)
+       {
+         int rfd = -1;
+         int wfd = -1;
+
+         bool jobserver
+           = (sscanf (n + strlen (needle), "%d,%d", &rfd, &wfd) == 2
+              && rfd > 0
+              && wfd > 0
+              && is_valid_fd (rfd)
+              && is_valid_fd (wfd));
+
+         /* Drop the jobserver if it's not working now.  */
+         if (!jobserver)
+           {
+             unsigned offset = n - makeflags;
+             char *dup = xstrdup (makeflags);
+             dup[offset] = '\0';
+
+             const char *space = strchr (makeflags + offset, ' ');
+             if (space != NULL)
+               strcpy (dup + offset, space);
+             xputenv (concat ("MAKEFLAGS=", dup, NULL));
+           }
+       }
+    }
+}
+
 /* Determine what the exit code of the driver should be.  */
 
 int
@@ -8269,7 +9116,17 @@ lookup_compiler (const char *name, size_t length, const char *language)
     {
       for (cp = compilers + n_compilers - 1; cp >= compilers; cp--)
        if (cp->suffix[0] == '@' && !strcmp (cp->suffix + 1, language))
-         return cp;
+         {
+           if (name != NULL && strcmp (name, "-") == 0
+               && (strcmp (cp->suffix, "@c-header") == 0
+                   || strcmp (cp->suffix, "@c++-header") == 0)
+               && !have_E)
+             fatal_error (input_location,
+                          "cannot use %<-%> as input filename for a "
+                          "precompiled header");
+
+           return cp;
+         }
 
       error ("language %s not recognized", language);
       return 0;
@@ -8326,24 +9183,12 @@ save_string (const char *s, int len)
 {
   char *result = XNEWVEC (char, len + 1);
 
+  gcc_checking_assert (strlen (s) >= (unsigned int) len);
   memcpy (result, s, len);
   result[len] = 0;
   return result;
 }
 
-void
-pfatal_with_name (const char *name)
-{
-  perror_with_name (name);
-  delete_temp_files ();
-  exit (1);
-}
-
-static void
-perror_with_name (const char *name)
-{
-  error ("%s: %m", name);
-}
 \f
 static inline void
 validate_switches_from_spec (const char *spec, bool user)
@@ -8351,9 +9196,13 @@ validate_switches_from_spec (const char *spec, bool user)
   const char *p = spec;
   char c;
   while ((c = *p++))
-    if (c == '%' && (*p == '{' || *p == '<' || (*p == 'W' && *++p == '{')))
+    if (c == '%'
+       && (*p == '{'
+           || *p == '<'
+           || (*p == 'W' && *++p == '{')
+           || (*p == '@' && *++p == '{')))
       /* We have a switch spec.  */
-      p = validate_switches (p + 1, user);
+      p = validate_switches (p + 1, user, *p == '{');
 }
 
 static void
@@ -8372,11 +9221,15 @@ validate_all_switches (void)
   validate_switches_from_spec (link_command_spec, false);
 }
 
-/* Look at the switch-name that comes after START
-   and mark as valid all supplied switches that match it.  */
+/* Look at the switch-name that comes after START and mark as valid
+   all supplied switches that match it.  If BRACED, handle other
+   switches after '|' and '&', and specs after ':' until ';' or '}',
+   going back for more switches after ';'.  Without BRACED, handle
+   only one atom.  Return a pointer to whatever follows the handled
+   items, after the closing brace if BRACED.  */
 
 static const char *
-validate_switches (const char *start, bool user_spec)
+validate_switches (const char *start, bool user_spec, bool braced)
 {
   const char *p = start;
   const char *atom;
@@ -8418,6 +9271,9 @@ next_member:
              switches[i].validated = true;
     }
 
+  if (!braced)
+    return p;
+
   if (*p) p++;
   if (*p && (p[-1] == '|' || p[-1] == '&'))
     goto next_member;
@@ -8430,9 +9286,11 @@ next_member:
            {
              p++;
              if (*p == '{' || *p == '<')
-               p = validate_switches (p+1, user_spec);
+               p = validate_switches (p+1, user_spec, *p == '{');
              else if (p[0] == 'W' && p[1] == '{')
-               p = validate_switches (p+2, user_spec);
+               p = validate_switches (p+2, user_spec, true);
+             else if (p[0] == '@' && p[1] == '{')
+               p = validate_switches (p+2, user_spec, true);
            }
          else
            p++;
@@ -8459,7 +9317,7 @@ static int n_mdswitches;
 /* Check whether a particular argument was used.  The first time we
    canonicalize the switches to keep only the ones we care about.  */
 
-class used_arg_t
+struct used_arg_t
 {
  public:
   int operator () (const char *p, int len);
@@ -8918,6 +9776,7 @@ print_multilib_info (void)
   const char *p = multilib_select;
   const char *last_path = 0, *this_path;
   int skip;
+  int not_arg;
   unsigned int last_path_len = 0;
 
   while (*p != '\0')
@@ -9072,9 +9931,13 @@ print_multilib_info (void)
                goto invalid_select;
 
              if (*q == '!')
-               arg = NULL;
+               {
+                 not_arg = 1;
+                 q++;
+               }
              else
-               arg = q;
+               not_arg = 0;
+             arg = q;
 
              while (*q != ' ' && *q != ';')
                {
@@ -9083,11 +9946,17 @@ print_multilib_info (void)
                  ++q;
                }
 
-             if (arg != NULL
-                 && default_arg (arg, q - arg))
+             if (default_arg (arg, q - arg))
                {
-                 skip = 1;
-                 break;
+                 /* Stop checking if any default arguments appeared in not
+                    list.  */
+                 if (not_arg)
+                   {
+                     skip = 0;
+                     break;
+                   }
+                 else
+                   skip = 1;
                }
 
              if (*q == ' ')
@@ -9170,7 +10039,11 @@ print_multilib_info (void)
    Returns the value of the environment variable given by its first argument,
    concatenated with the second argument.  If the variable is not defined, a
    fatal error is issued unless such undefs are internally allowed, in which
-   case the variable name is used as the variable value.  */
+   case the variable name prefixed by a '/' is used as the variable value.
+
+   The leading '/' allows using the result at a spot where a full path would
+   normally be expected and when the actual value doesn't really matter since
+   undef vars are allowed.  */
 
 static const char *
 getenv_spec_function (int argc, const char **argv)
@@ -9188,8 +10061,15 @@ getenv_spec_function (int argc, const char **argv)
   varname = argv[0];
   value = env.get (varname);
 
+  /* If the variable isn't defined and this is allowed, craft our expected
+     return value.  Assume variable names used in specs strings don't contain
+     any active spec character so don't need escaping.  */
   if (!value && spec_undefvar_allowed)
-    value = varname;
+    {
+      result = XNEWVAR (char, strlen(varname) + 2);
+      sprintf (result, "/%s", varname);
+      return result;
+    }
 
   if (!value)
     fatal_error (input_location,
@@ -9248,6 +10128,29 @@ if_exists_else_spec_function (int argc, const char **argv)
   return argv[1];
 }
 
+/* if-exists-then-else built-in spec function.
+
+   Checks to see if the file specified by the absolute pathname in
+   the first arg exists.  Returns the second arg if so, otherwise returns
+   the third arg if it is present.  */
+
+static const char *
+if_exists_then_else_spec_function (int argc, const char **argv)
+{
+
+  /* Must have two or three arguments.  */
+  if (argc != 2 && argc != 3)
+    return NULL;
+
+  if (IS_ABSOLUTE_PATH (argv[0]) && ! access (argv[0], R_OK))
+    return argv[1];
+
+  if (argc == 3)
+    return argv[2];
+
+  return NULL;
+}
+
 /* sanitize built-in spec function.
 
    This returns non-NULL, if sanitizing address, thread or
@@ -9261,12 +10164,17 @@ sanitize_spec_function (int argc, const char **argv)
 
   if (strcmp (argv[0], "address") == 0)
     return (flag_sanitize & SANITIZE_USER_ADDRESS) ? "" : NULL;
+  if (strcmp (argv[0], "hwaddress") == 0)
+    return (flag_sanitize & SANITIZE_USER_HWADDRESS) ? "" : NULL;
   if (strcmp (argv[0], "kernel-address") == 0)
     return (flag_sanitize & SANITIZE_KERNEL_ADDRESS) ? "" : NULL;
+  if (strcmp (argv[0], "kernel-hwaddress") == 0)
+    return (flag_sanitize & SANITIZE_KERNEL_HWADDRESS) ? "" : NULL;
   if (strcmp (argv[0], "thread") == 0)
     return (flag_sanitize & SANITIZE_THREAD) ? "" : NULL;
   if (strcmp (argv[0], "undefined") == 0)
-    return ((flag_sanitize & (SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT))
+    return ((flag_sanitize
+            & (SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT))
            && !flag_sanitize_undefined_trap_on_error) ? "" : NULL;
   if (strcmp (argv[0], "leak") == 0)
     return ((flag_sanitize
@@ -9554,11 +10462,11 @@ compare_debug_dump_opt_spec_function (int arg,
     fatal_error (input_location,
                 "too many arguments to %%:compare-debug-dump-opt");
 
-  do_spec_2 ("%{fdump-final-insns=*:%*}");
+  do_spec_2 ("%{fdump-final-insns=*:%*}", NULL);
   do_spec_1 (" ", 0, NULL);
 
   if (argbuf.length () > 0
-      && strcmp (argv[argbuf.length () - 1], "."))
+      && strcmp (argv[argbuf.length () - 1], ".") != 0)
     {
       if (!compare_debug)
        return NULL;
@@ -9568,25 +10476,22 @@ compare_debug_dump_opt_spec_function (int arg,
     }
   else
     {
-      const char *ext = NULL;
-
       if (argbuf.length () > 0)
-       {
-         do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}");
-         ext = ".gkd";
-       }
+       do_spec_2 ("%B.gkd", NULL);
       else if (!compare_debug)
        return NULL;
       else
-       do_spec_2 ("%g.gkd");
+       do_spec_2 ("%{!save-temps*:%g.gkd}%{save-temps*:%B.gkd}", NULL);
 
       do_spec_1 (" ", 0, NULL);
 
       gcc_assert (argbuf.length () > 0);
 
-      name = concat (argbuf.last (), ext, NULL);
+      name = xstrdup (argbuf.last ());
 
-      ret = concat ("-fdump-final-insns=", name, NULL);
+      char *arg = quote_spec (xstrdup (name));
+      ret = concat ("-fdump-final-insns=", arg, NULL);
+      free (arg);
     }
 
   which = compare_debug < 0;
@@ -9613,8 +10518,6 @@ compare_debug_dump_opt_spec_function (int arg,
   return ret;
 }
 
-static const char *debug_auxbase_opt;
-
 /* %:compare-debug-self-opt spec function.  Expands to the options
     that are to be passed in the second compilation of
     compare-debug.  */
@@ -9630,16 +10533,6 @@ compare_debug_self_opt_spec_function (int arg,
   if (compare_debug >= 0)
     return NULL;
 
-  do_spec_2 ("%{c|S:%{o*:%*}}");
-  do_spec_1 (" ", 0, NULL);
-
-  if (argbuf.length () > 0)
-    debug_auxbase_opt = concat ("-auxbase-strip ",
-                               argbuf.last (),
-                               NULL);
-  else
-    debug_auxbase_opt = NULL;
-
   return concat ("\
 %<o %<MD %<MMD %<MF* %<MG %<MP %<MQ* %<MT* \
 %<fdump-final-insns=* -w -S -o %j \
@@ -9647,50 +10540,6 @@ compare_debug_self_opt_spec_function (int arg,
 ", compare_debug_opt, NULL);
 }
 
-/* %:compare-debug-auxbase-opt spec function.  Expands to the auxbase
-    options that are to be passed in the second compilation of
-    compare-debug.  It expects, as an argument, the basename of the
-    current input file name, with the .gk suffix appended to it.  */
-
-static const char *
-compare_debug_auxbase_opt_spec_function (int arg,
-                                        const char **argv)
-{
-  char *name;
-  int len;
-
-  if (arg == 0)
-    fatal_error (input_location,
-                "too few arguments to %%:compare-debug-auxbase-opt");
-
-  if (arg != 1)
-    fatal_error (input_location,
-                "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_error (input_location, "argument to %%:compare-debug-auxbase-opt "
-                "does not end in .gk");
-
-  if (debug_auxbase_opt)
-    return debug_auxbase_opt;
-
-#define OPT "-auxbase "
-
-  len -= 3;
-  name = (char*) xmalloc (sizeof (OPT) + len);
-  memcpy (name, OPT, sizeof (OPT) - 1);
-  memcpy (name + sizeof (OPT) - 1, argv[0], len);
-  name[sizeof (OPT) - 1 + len] = '\0';
-
-#undef OPT
-
-  return name;
-}
-
 /* %:pass-through-libs spec function.  Finds all -l options and input
    file names in the lib spec passed to it, and makes a list of them
    prepended with the plugin option to cause them to be passed through
@@ -9734,37 +10583,108 @@ pass_through_libs_spec_func (int argc, const char **argv)
   return prepended;
 }
 
-/* %:replace-extension spec function.  Replaces the extension of the
-   first argument with the second argument.  */
+static bool
+not_actual_file_p (const char *name)
+{
+  return (strcmp (name, "-") == 0
+         || strcmp (name, HOST_BIT_BUCKET) == 0);
+}
 
+/* %:dumps spec function.  Take an optional argument that overrides
+   the default extension for -dumpbase and -dumpbase-ext.
+   Return -dumpdir, -dumpbase and -dumpbase-ext, if needed.  */
 const char *
-replace_extension_spec_func (int argc, const char **argv)
+dumps_spec_func (int argc, const char **argv ATTRIBUTE_UNUSED)
 {
-  char *name;
+  const char *ext = dumpbase_ext;
   char *p;
-  char *result;
-  int i;
 
-  if (argc != 2)
-    fatal_error (input_location, "too few arguments to %%:replace-extension");
+  char *args[3] = { NULL, NULL, NULL };
+  int nargs = 0;
 
-  name = xstrdup (argv[0]);
+  /* Do not compute a default for -dumpbase-ext when -dumpbase was
+     given explicitly.  */
+  if (dumpbase && *dumpbase && !ext)
+    ext = "";
 
-  for (i = strlen (name) - 1; i >= 0; i--)
-    if (IS_DIR_SEPARATOR (name[i]))
-      break;
+  if (argc == 1)
+    {
+      /* Do not override the explicitly-specified -dumpbase-ext with
+        the specs-provided overrider.  */
+      if (!ext)
+       ext = argv[0];
+    }
+  else if (argc != 0)
+    fatal_error (input_location, "too many arguments for %%:dumps");
 
-  p = strrchr (name + i + 1, '.');
-  if (p != NULL)
-      *p = '\0';
+  if (dumpdir)
+    {
+      p = quote_spec_arg (xstrdup (dumpdir));
+      args[nargs++] = concat (" -dumpdir ", p, NULL);
+      free (p);
+    }
 
-  result = concat (name, argv[1], NULL);
+  if (!ext)
+    ext = input_basename + basename_length;
 
-  free (name);
-  return result;
+  /* Use the precomputed outbase, or compute dumpbase from
+     input_basename, just like %b would.  */
+  char *base;
+
+  if (dumpbase && *dumpbase)
+    {
+      base = xstrdup (dumpbase);
+      p = base + outbase_length;
+      gcc_checking_assert (strncmp (base, outbase, outbase_length) == 0);
+      gcc_checking_assert (strcmp (p, ext) == 0);
+    }
+  else if (outbase_length)
+    {
+      base = xstrndup (outbase, outbase_length);
+      p = NULL;
+    }
+  else
+    {
+      base = xstrndup (input_basename, suffixed_basename_length);
+      p = base + basename_length;
+    }
+
+  if (compare_debug < 0 || !p || strcmp (p, ext) != 0)
+    {
+      if (p)
+       *p = '\0';
+
+      const char *gk;
+      if (compare_debug < 0)
+       gk = ".gk";
+      else
+       gk = "";
+
+      p = concat (base, gk, ext, NULL);
+
+      free (base);
+      base = p;
+    }
+
+  base = quote_spec_arg (base);
+  args[nargs++] = concat (" -dumpbase ", base, NULL);
+  free (base);
+
+  if (*ext)
+    {
+      p = quote_spec_arg (xstrdup (ext));
+      args[nargs++] = concat (" -dumpbase-ext ", p, NULL);
+      free (p);
+    }
+
+  const char *ret = concat (args[0], args[1], args[2], NULL);
+  while (nargs > 0)
+    free (args[--nargs]);
+
+  return ret;
 }
 
-/* Returns "" if the n in ARGV[1] == -opt=<n> is greater than ARGV[2].
+/* Returns "" if ARGV[ARGC - 2] is greater than ARGV[ARGC-1].
    Otherwise, return NULL.  */
 
 static const char *
@@ -9775,36 +10695,158 @@ greater_than_spec_func (int argc, const char **argv)
   if (argc == 1)
     return NULL;
 
-  gcc_assert (argc == 3);
-  gcc_assert (argv[0][0] == '-');
-  gcc_assert (argv[0][1] == '\0');
+  gcc_assert (argc >= 2);
 
-  /* Point p to <n> in in -opt=<n>.  */
-  const char *p = argv[1];
-  while (true)
-    {
-      char c = *p;
-      if (c == '\0')
-       gcc_unreachable ();
+  long arg = strtol (argv[argc - 2], &converted, 10);
+  gcc_assert (converted != argv[argc - 2]);
 
-      ++p;
+  long lim = strtol (argv[argc - 1], &converted, 10);
+  gcc_assert (converted != argv[argc - 1]);
 
-      if (c == '=')
-       break;
-    }
+  if (arg > lim)
+    return "";
+
+  return NULL;
+}
 
-  long arg = strtol (p, &converted, 10);
-  gcc_assert (converted != p);
+/* Returns "" if debug_info_level is greater than ARGV[ARGC-1].
+   Otherwise, return NULL.  */
 
-  long lim = strtol (argv[2], &converted, 10);
-  gcc_assert (converted != argv[2]);
+static const char *
+debug_level_greater_than_spec_func (int argc, const char **argv)
+{
+  char *converted;
 
-  if (arg > lim)
+  if (argc != 1)
+    fatal_error (input_location,
+                "wrong number of arguments to %%:debug-level-gt");
+
+  long arg = strtol (argv[0], &converted, 10);
+  gcc_assert (converted != argv[0]);
+
+  if (debug_info_level > arg)
     return "";
 
   return NULL;
 }
 
+/* Returns "" if dwarf_version is greater than ARGV[ARGC-1].
+   Otherwise, return NULL.  */
+
+static const char *
+dwarf_version_greater_than_spec_func (int argc, const char **argv)
+{
+  char *converted;
+
+  if (argc != 1)
+    fatal_error (input_location,
+                "wrong number of arguments to %%:dwarf-version-gt");
+
+  long arg = strtol (argv[0], &converted, 10);
+  gcc_assert (converted != argv[0]);
+
+  if (dwarf_version > arg)
+    return "";
+
+  return NULL;
+}
+
+static void
+path_prefix_reset (path_prefix *prefix)
+{
+  struct prefix_list *iter, *next;
+  iter = prefix->plist;
+  while (iter)
+    {
+      next = iter->next;
+      free (const_cast <char *> (iter->prefix));
+      XDELETE (iter);
+      iter = next;
+    }
+  prefix->plist = 0;
+  prefix->max_len = 0;
+}
+
+/* The function takes 3 arguments: OPTION name, file name and location
+   where we search for Fortran modules.
+   When the FILE is found by find_file, return OPTION=path_to_file.  */
+
+static const char *
+find_fortran_preinclude_file (int argc, const char **argv)
+{
+  char *result = NULL;
+  if (argc != 3)
+    return NULL;
+
+  struct path_prefix prefixes = { 0, 0, "preinclude" };
+
+  /* Search first for 'finclude' folder location for a header file
+     installed by the compiler (similar to omp_lib.h).  */
+  add_prefix (&prefixes, argv[2], NULL, 0, 0, 0);
+#ifdef TOOL_INCLUDE_DIR
+  /* Then search: <prefix>/<target>/<include>/finclude */
+  add_prefix (&prefixes, TOOL_INCLUDE_DIR "/finclude/",
+             NULL, 0, 0, 0);
+#endif
+#ifdef NATIVE_SYSTEM_HEADER_DIR
+  /* Then search: <sysroot>/usr/include/finclude/<multilib> */
+  add_sysrooted_hdrs_prefix (&prefixes, NATIVE_SYSTEM_HEADER_DIR "/finclude/",
+                            NULL, 0, 0, 0);
+#endif
+
+  const char *path = find_a_file (&include_prefixes, argv[1], R_OK, false);
+  if (path != NULL)
+    result = concat (argv[0], path, NULL);
+  else
+    {
+      path = find_a_file (&prefixes, argv[1], R_OK, false);
+      if (path != NULL)
+       result = concat (argv[0], path, NULL);
+    }
+
+  path_prefix_reset (&prefixes);
+  return result;
+}
+
+/* If any character in ORIG fits QUOTE_P (_, P), reallocate the string
+   so as to precede every one of them with a backslash.  Return the
+   original string or the reallocated one.  */
+
+static inline char *
+quote_string (char *orig, bool (*quote_p)(char, void *), void *p)
+{
+  int len, number_of_space = 0;
+
+  for (len = 0; orig[len]; len++)
+    if (quote_p (orig[len], p))
+      number_of_space++;
+
+  if (number_of_space)
+    {
+      char *new_spec = (char *) xmalloc (len + number_of_space + 1);
+      int j, k;
+      for (j = 0, k = 0; j <= len; j++, k++)
+       {
+         if (quote_p (orig[j], p))
+           new_spec[k++] = '\\';
+         new_spec[k] = orig[j];
+       }
+      free (orig);
+      return new_spec;
+    }
+  else
+    return orig;
+}
+
+/* Return true iff C is any of the characters convert_white_space
+   should quote.  */
+
+static inline bool
+whitespace_to_convert_p (char c, void *)
+{
+  return (c == ' ' || c == '\t');
+}
+
 /* Insert backslash before spaces in ORIG (usually a file path), to 
    avoid being broken by spec parser.
 
@@ -9831,42 +10873,50 @@ greater_than_spec_func (int argc, const char **argv)
 static char *
 convert_white_space (char *orig)
 {
-  int len, number_of_space = 0;
-
-  for (len = 0; orig[len]; len++)
-    if (orig[len] == ' ' || orig[len] == '\t') number_of_space++;
+  return quote_string (orig, whitespace_to_convert_p, NULL);
+}
 
-  if (number_of_space)
+/* Return true iff C matches any of the spec active characters.  */
+static inline bool
+quote_spec_char_p (char c, void *)
+{
+  switch (c)
     {
-      char *new_spec = (char *) xmalloc (len + number_of_space + 1);
-      int j, k;
-      for (j = 0, k = 0; j <= len; j++, k++)
-       {
-         if (orig[j] == ' ' || orig[j] == '\t')
-           new_spec[k++] = '\\';
-         new_spec[k] = orig[j];
-       }
-      free (orig);
-      return new_spec;
-  }
-  else
-    return orig;
+    case ' ':
+    case '\t':
+    case '\n':
+    case '|':
+    case '%':
+    case '\\':
+      return true;
+
+    default:
+      return false;
+    }
 }
 
-static void
-path_prefix_reset (path_prefix *prefix)
+/* Like convert_white_space, but deactivate all active spec chars by
+   quoting them.  */
+
+static inline char *
+quote_spec (char *orig)
 {
-  struct prefix_list *iter, *next;
-  iter = prefix->plist;
-  while (iter)
+  return quote_string (orig, quote_spec_char_p, NULL);
+}
+
+/* Like quote_spec, but also turn an empty string into the spec for an
+   empty argument.  */
+
+static inline char *
+quote_spec_arg (char *orig)
+{
+  if (!*orig)
     {
-      next = iter->next;
-      free (const_cast <char *> (iter->prefix));
-      XDELETE (iter);
-      iter = next;
+      free (orig);
+      return xstrdup ("%\"");
     }
-  prefix->plist = 0;
-  prefix->max_len = 0;
+
+  return quote_spec (orig);
 }
 
 /* Restore all state within gcc.c to the initial state, so that the driver
@@ -9888,7 +10938,6 @@ void
 driver::finalize ()
 {
   env.restore ();
-  params_c_finalize ();
   diagnostic_finish (global_dc);
 
   is_cpp_driver = 0;
@@ -9904,14 +10953,17 @@ driver::finalize ()
   target_sysroot_suffix = 0;
   target_sysroot_hdrs_suffix = 0;
   save_temps_flag = SAVE_TEMPS_NONE;
-  save_temps_prefix = 0;
-  save_temps_length = 0;
+  save_temps_overrides_dumpdir = false;
+  dumpdir_trailing_dash_added = false;
+  free (dumpdir);
+  free (dumpbase);
+  free (dumpbase_ext);
+  free (outbase);
+  dumpdir = dumpbase = dumpbase_ext = outbase = NULL;
+  dumpdir_length = outbase_length = 0;
   spec_machine = DEFAULT_TARGET_MACHINE;
   greatest_status = 1;
 
-  finalize_options_struct (&global_options);
-  finalize_options_struct (&global_options_set);
-
   obstack_free (&obstack, NULL);
   obstack_free (&opts_obstack, NULL); /* in opts.c */
   obstack_free (&collect_obstack, NULL);
@@ -9947,9 +10999,9 @@ driver::finalize ()
   just_machine_suffix = 0;
   gcc_exec_prefix = 0;
   gcc_libexec_prefix = 0;
-  md_exec_prefix = MD_EXEC_PREFIX;
-  md_startfile_prefix = MD_STARTFILE_PREFIX;
-  md_startfile_prefix_1 = MD_STARTFILE_PREFIX_1;
+  set_static_spec_shared (&md_exec_prefix, MD_EXEC_PREFIX);
+  set_static_spec_shared (&md_startfile_prefix, MD_STARTFILE_PREFIX);
+  set_static_spec_shared (&md_startfile_prefix_1, MD_STARTFILE_PREFIX_1);
   multilib_dir = 0;
   multilib_os_dir = 0;
   multiarch_dir = 0;
@@ -9973,8 +11025,7 @@ driver::finalize ()
       spec_list *sl = &static_specs[i];
       if (sl->alloc_p)
        {
-         if (0)
-           free (const_cast <char *> (*(sl->ptr_spec)));
+         free (const_cast <char *> (*(sl->ptr_spec)));
          sl->alloc_p = false;
        }
       *(sl->ptr_spec) = sl->default_ptr;
@@ -9985,7 +11036,7 @@ driver::finalize ()
 
   processing_spec_function = 0;
 
-  argbuf.truncate (0);
+  clear_args ();
 
   have_c = 0;
   have_o = 0;
@@ -10047,8 +11098,6 @@ driver::finalize ()
   mdswitches = NULL;
   n_mdswitches = 0;
 
-  debug_auxbase_opt = NULL;
-
   used_arg.finalize ();
 }