diff gcc/gcc.c @ 132:d34655255c78

update gcc-8.2
author mir3636
date Thu, 25 Oct 2018 10:21:07 +0900
parents ab0bcb71f44d 84e7813d76e9
children 351920fa3827
line wrap: on
line diff
--- a/gcc/gcc.c	Thu Oct 25 08:08:40 2018 +0900
+++ b/gcc/gcc.c	Thu Oct 25 10:21:07 2018 +0900
@@ -1,5 +1,5 @@
 /* Compiler driver program that can handle many languages.
-   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+   Copyright (C) 1987-2018 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -36,6 +36,7 @@
 #include "obstack.h"
 #include "intl.h"
 #include "prefix.h"
+#include "opt-suggestions.h"
 #include "gcc.h"
 #include "diagnostic.h"
 #include "flags.h"
@@ -170,9 +171,10 @@
 
 
 /* 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 +221,10 @@
 
 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
@@ -349,12 +355,12 @@
 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 *);
@@ -366,7 +372,6 @@
 static int default_arg (const char *, int);
 static void set_multilib_dir (void);
 static void print_multilib_info (void);
-static void perror_with_name (const char *);
 static void display_help (void);
 static void add_preprocessor_option (const char *, int);
 static void add_assembler_option (const char *, int);
@@ -475,8 +480,11 @@
 	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.
@@ -683,7 +691,7 @@
 
 #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)
@@ -701,7 +709,7 @@
 
 #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)
@@ -719,7 +727,7 @@
 
 #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)
@@ -737,7 +745,7 @@
 
 #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 "}" \
@@ -863,7 +871,7 @@
    -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
@@ -960,6 +968,7 @@
     -plugin %(linker_plugin_file) \
     -plugin-opt=%(lto_wrapper) \
     -plugin-opt=-fresolution=%u.res \
+    %{flinker-output=*:-plugin-opt=-linker-output-known} \
     %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} \
     }" PLUGIN_COND_CLOSE
 #else
@@ -971,20 +980,20 @@
 /* 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(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(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
@@ -998,8 +1007,8 @@
 #ifndef VTABLE_VERIFICATION_SPEC
 #if ENABLE_VTABLE_VERIFY
 #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}}"
+%{!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 "\
 %{fvtable-verify=none:} \
@@ -1010,10 +1019,6 @@
 #endif
 #endif
 
-#ifndef CHKP_SPEC
-#define CHKP_SPEC ""
-#endif
-
 /* -u* was put back because both BSD and SysV seem to support it.  */
 /* %{static|no-pie|static-pie:} simply prevents an error message:
    1. If the target machine doesn't handle -static.
@@ -1035,17 +1040,16 @@
     %{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|no-pie|static-pie:} %{L*} %(mfwrap) %(link_libgcc) " \
-    VTABLE_VERIFICATION_SPEC " " SANITIZER_EARLY_SPEC " %o " CHKP_SPEC " \
+    %{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
@@ -1112,12 +1116,12 @@
    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*}\
  %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}}\
- %{remap} %{g3|ggdb3|gstabs3|gcoff3|gxcoff3|gvms3:-dD}\
+ %{remap} %{g3|ggdb3|gstabs3|gxcoff3|gvms3:-dD}\
  %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
  %{H} %C %{D*&U*&A*} %{i*} %Z %i\
  %{E|M|MM:%W{o*}}";
@@ -1215,15 +1219,9 @@
 #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
@@ -1936,9 +1934,14 @@
 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;
 
@@ -1978,6 +1981,7 @@
 alloc_args (void)
 {
   argbuf.create (10);
+  at_file_argbuf.create (10);
 }
 
 /* Clear out the vector of arguments (after a command is executed).  */
@@ -1986,6 +1990,7 @@
 clear_args (void)
 {
   argbuf.truncate (0);
+  at_file_argbuf.truncate (0);
 }
 
 /* Add one argument to the vector at the end.
@@ -1998,7 +2003,10 @@
 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)
     {
@@ -2011,6 +2019,67 @@
       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);
+}
 
 /* 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
@@ -2033,15 +2102,20 @@
   /* 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);
 
@@ -2422,7 +2496,7 @@
     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
 
@@ -3101,13 +3175,11 @@
 			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)
@@ -3827,6 +3899,11 @@
       add_linker_option ("--version", strlen ("--version"));
       break;
 
+    case OPT__completion_:
+      validated = true;
+      completion = decoded->arg;
+      break;
+
     case OPT__help:
       print_help_list = 1;
 
@@ -4472,10 +4549,8 @@
 
           if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
 	    {
-	      if (fname[0] == '@' && access (fname + 1, F_OK) < 0)
-		perror_with_name (fname + 1);
-	      else
-		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);
@@ -4867,7 +4942,7 @@
 {
   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 `|'.  */
@@ -4886,8 +4961,11 @@
   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;
 
@@ -4900,14 +4978,13 @@
   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.  */
 
@@ -4965,7 +5042,7 @@
 {
   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.
@@ -5093,39 +5170,6 @@
   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
@@ -5317,7 +5361,7 @@
 	      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++;
 	    }
@@ -5538,41 +5582,22 @@
 	  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;
-
-		    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;
-		      }
+		  open_at_file ();
+
+		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
 	      {
@@ -5645,45 +5670,20 @@
 	    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));
@@ -5724,6 +5724,20 @@
 	      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':
 	    {
@@ -5868,7 +5882,7 @@
 	    break;
 
 	  case ':':
-	    p = handle_spec_function (p, NULL);
+	    p = handle_spec_function (p, NULL, soft_matched_part);
 	    if (p == 0)
 	      return -1;
 	    break;
@@ -6030,7 +6044,8 @@
 /* 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;
@@ -6080,7 +6095,7 @@
      arguments.  */
 
   alloc_args ();
-  if (do_spec_2 (args) < 0)
+  if (do_spec_2 (args, soft_matched_part) < 0)
     fatal_error (input_location, "error in args to spec function %qs", func);
 
   /* argbuf_index is an index for the next argument to be inserted, and
@@ -6117,10 +6132,14 @@
    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;
@@ -6163,7 +6182,7 @@
 
   /* 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)
@@ -6317,7 +6336,7 @@
 	{
 	  atom = NULL;
 	  end_atom = NULL;
-	  p = handle_spec_function (p + 2, &a_matched);
+	  p = handle_spec_function (p + 2, &a_matched, NULL);
 	}
       else
 	{
@@ -6869,13 +6888,11 @@
 		    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))
@@ -7044,8 +7061,8 @@
 
     /* 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:
@@ -7271,8 +7288,7 @@
 
 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);
 }
@@ -7281,14 +7297,6 @@
 {
   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.  */
@@ -7309,6 +7317,12 @@
   maybe_putenv_OFFLOAD_TARGETS ();
   handle_unrecognized_options ();
 
+  if (completion)
+    {
+      m_option_proposer.suggest_completion (completion);
+      return 0;
+    }
+
   if (!maybe_print_and_exit ())
     return 0;
 
@@ -7555,7 +7569,7 @@
   /* 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");
@@ -7579,7 +7593,7 @@
   /* 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");
@@ -7589,7 +7603,7 @@
 
   /* 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;
@@ -7777,106 +7791,6 @@
   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, option,
-					      with_arg);
-		  free (with_arg);
-		}
-	    }
-	  else
-	    add_misspelling_candidates (m_option_suggestions, option,
-					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)
-	      {
-		struct cl_option optb;
-		/* -fsanitize=all is not valid, only -fno-sanitize=all.
-		   So don't register the positive misspelling candidates
-		   for it.  */
-		if (sanitizer_opts[j].flag == ~0U && i == OPT_fsanitize_)
-		  {
-		    optb = *option;
-		    optb.opt_text = opt_text = "-fno-sanitize=";
-		    optb.cl_reject_negative = true;
-		    option = &optb;
-		  }
-		/* 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, option,
-					    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
@@ -7885,7 +7799,7 @@
   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%>;"
 		 " did you mean %<-%s%>?",
@@ -8044,7 +7958,7 @@
     {
       printf (_("%s %s%s\n"), progname, pkgversion_string,
 	      version_string);
-      printf ("Copyright %s 2017 Free Software Foundation, Inc.\n",
+      printf ("Copyright %s 2018 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"),
@@ -8194,7 +8108,8 @@
 	      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];
@@ -8219,7 +8134,7 @@
 					       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;
@@ -8492,19 +8407,6 @@
   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);
-}
 
 static inline void
 validate_switches_from_spec (const char *spec, bool user)
@@ -8512,7 +8414,11 @@
   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);
 }
@@ -8594,6 +8500,8 @@
 		p = validate_switches (p+1, user_spec);
 	      else if (p[0] == 'W' && p[1] == '{')
 		p = validate_switches (p+2, user_spec);
+	      else if (p[0] == '@' && p[1] == '{')
+		p = validate_switches (p+2, user_spec);
 	    }
 	  else
 	    p++;
@@ -9331,7 +9239,11 @@
    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)
@@ -9349,8 +9261,15 @@
   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,
@@ -9716,7 +9635,7 @@
     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
@@ -9734,13 +9653,13 @@
 
       if (argbuf.length () > 0)
 	{
-	  do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}");
+	  do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}", NULL);
 	  ext = ".gkd";
 	}
       else if (!compare_debug)
 	return NULL;
       else
-	do_spec_2 ("%g.gkd");
+	do_spec_2 ("%g.gkd", NULL);
 
       do_spec_1 (" ", 0, NULL);
 
@@ -9792,7 +9711,7 @@
   if (compare_debug >= 0)
     return NULL;
 
-  do_spec_2 ("%{c|S:%{o*:%*}}");
+  do_spec_2 ("%{c|S:%{o*:%*}}", NULL);
   do_spec_1 (" ", 0, NULL);
 
   if (argbuf.length () > 0)
@@ -10152,7 +10071,7 @@
 
   processing_spec_function = 0;
 
-  argbuf.truncate (0);
+  clear_args ();
 
   have_c = 0;
   have_o = 0;