OSDN Git Service

* c-decl.c (finish_function): Warn about a non-void function with
[pf3gnuchains/gcc-fork.git] / gcc / gcc.c
index cb2e47b..41c62a9 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -1,6 +1,6 @@
 /* Compiler driver program that can handle many languages.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -143,6 +143,9 @@ static const char dir_separator_str[] = { DIR_SEPARATOR, 0 };
 
 #define MIN_FATAL_STATUS 1
 
+/* Flag set by cppspec.c to 1.  */
+int is_cpp_driver;
+
 /* Flag saying to pass the greatest exit code returned by a sub-process
    to the calling program.  */
 static int pass_exit_codes;
@@ -183,6 +186,13 @@ static int print_help_list;
 
 static int verbose_flag;
 
+/* Flag indicating whether we should ONLY print the command and
+   arguments (like verbose_flag) without executing the command.
+   Displayed arguments are quoted so that the generated command
+   line is suitable for execution.  This is intended for use in
+   shell scripts to capture the driver-generated command line.  */
+static int verbose_only_flag;
+
 /* Flag indicating to print target specific command line options.  */
 
 static int target_help_flag;
@@ -224,7 +234,7 @@ static const char *cross_compile = "0";
    switch.  The only case we support now is simply appending or deleting a
    string to or from the end of the first part of the configuration name.  */
 
-const struct modify_target
+static const struct modify_target
 {
   const char *const sw;
   const enum add_del {ADD, DELETE} add_del;
@@ -313,11 +323,11 @@ static void clear_args                    PARAMS ((void));
 static void fatal_error                        PARAMS ((int));
 #ifdef ENABLE_SHARED_LIBGCC
 static void init_gcc_specs              PARAMS ((struct obstack *,
-                                                const char *,
+                                                const char *, const char *,
                                                 const char *));
 #endif
 #if defined(HAVE_TARGET_OBJECT_SUFFIX) || defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
-static const char *convert_filename    PARAMS ((const char *, int));
+static const char *convert_filename    PARAMS ((const char *, int, int));
 #endif
 \f
 /* The Specs Language
@@ -435,7 +445,6 @@ or with constant text in a single argument.
        if multilib_dir is not set or is ".", output "".
  %S     process STARTFILE_SPEC as a spec.  A capital S is actually used here.
  %E     process ENDFILE_SPEC as a spec.  A capital E is actually used here.
- %c    process SIGNED_CHAR_SPEC as a spec.
  %C     process CPP_SPEC as a spec.
  %1    process CC1_SPEC as a spec.
  %2    process CC1PLUS_SPEC as a spec.
@@ -501,7 +510,7 @@ CC also knows implicitly that arguments starting in `-l' are to be
 treated as compiler output files, and passed to the linker in their
 proper position among the other output files.  */
 \f
-/* Define the macros used for specs %a, %l, %L, %S, %c, %C, %1.  */
+/* Define the macros used for specs %a, %l, %L, %S, %C, %1.  */
 
 /* config.h can define ASM_SPEC to provide extra args to the assembler
    or extra switch-translations.  */
@@ -572,17 +581,6 @@ proper position among the other output files.  */
 #define ENDFILE_SPEC ""
 #endif
 
-/* This spec is used for telling cpp whether char is signed or not.  */
-#ifndef SIGNED_CHAR_SPEC
-/* Use #if rather than ?:
-   because MIPS C compiler rejects like ?: in initializers.  */
-#if DEFAULT_SIGNED_CHAR
-#define SIGNED_CHAR_SPEC "%{funsigned-char:-D__CHAR_UNSIGNED__}"
-#else
-#define SIGNED_CHAR_SPEC "%{!fsigned-char:-D__CHAR_UNSIGNED__}"
-#endif
-#endif
-
 #ifndef LINKER_NAME
 #define LINKER_NAME "collect2"
 #endif
@@ -641,7 +639,6 @@ static const char *cpp_spec = CPP_SPEC;
 static const char *cpp_predefines = CPP_PREDEFINES;
 static const char *cc1_spec = CC1_SPEC;
 static const char *cc1plus_spec = CC1PLUS_SPEC;
-static const char *signed_char_spec = SIGNED_CHAR_SPEC;
 static const char *asm_spec = ASM_SPEC;
 static const char *asm_final_spec = ASM_FINAL_SPEC;
 static const char *link_spec = LINK_SPEC;
@@ -663,25 +660,30 @@ static const char *link_libgcc_spec = LINK_LIBGCC_SPEC;
 static const char *trad_capable_cpp =
 "%{traditional|ftraditional|traditional-cpp:trad}cpp0";
 
-static const char *cpp_options =
+static const char *cpp_unique_options =
 "%{C:%{!E:%eGNU C does not support -C without using -E}}\
- %{std*} %{nostdinc*}\
- %{C} %{v} %{I*} %{P} %{$} %I\
+ %{nostdinc*} %{C} %{v} %{I*} %{P} %{$} %I\
  %{MD:-M -MF %W{!o: %b.d}%W{o*:%.d%*}}\
  %{MMD:-MM -MF %W{!o: %b.d}%W{o*:%.d%*}}\
  %{M} %{MM} %W{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{M|MD|MM|MMD:%{o*:-MQ %*}}\
  %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2 -D__GNUC_PATCHLEVEL__=%v3}\
  %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs}\
- %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
  %{fno-inline|O0|!O*:-D__NO_INLINE__} %{ffast-math:-D__FAST_MATH__}\
  %{fshort-wchar:-U__WCHAR_TYPE__ -D__WCHAR_TYPE__=short\\ unsigned\\ int}\
  %{ffreestanding:-D__STDC_HOSTED__=0} %{fno-hosted:-D__STDC_HOSTED__=0}\
- %{!ffreestanding:%{!fno-hosted:-D__STDC_HOSTED__=1}}\
+ %{!ffreestanding:%{!fno-hosted:-D__STDC_HOSTED__=1}} %{remap}\
+ %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i\
+ %{E:%{!M*:%W{o*}}}";
+
+/* This contains cpp options which are common with cc1_options and are passed
+   only when preprocessing only to avoid duplication.  */
+static const char *cpp_options =
+"%(cpp_unique_options) %{std*} %{d*} %{W*} %{w} %{pedantic*}\
  %{fshow-column} %{fno-show-column}\
+ %{fsigned-char&funsigned-char}\
  %{fleading-underscore} %{fno-leading-underscore}\
- %{fno-operator-names} %{ftabstop=*} %{remap}\
- %{g3:-dD} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*&U*&A*} %{i*} %Z %i\
- %{E:%{!M*:%W{o*}}}";
+ %{fno-operator-names} %{ftabstop=*}";
 
 /* NB: This is shared amongst all front-ends.  */
 static const char *cc1_options =
@@ -797,7 +799,7 @@ static int n_compilers;
 
 /* The default list of file name suffixes and their compilation specs.  */
 
-static struct compiler default_compilers[] =
+static const struct compiler default_compilers[] =
 {
   /* Add lists of suffixes of known languages here.  If those languages
      were not present when we built the driver, we will hit these copies
@@ -830,7 +832,7 @@ static struct compiler default_compilers[] =
                tradcpp0 -lang-c %{ansi:-std=c89} %(cpp_options) %{!pipe:%g.i} |\n\
                    cc1 -fpreprocessed %{!pipe:%g.i} %(cc1_options)}\
            %{!traditional:%{!ftraditional:%{!traditional-cpp:\
-               cc1 -lang-c %{ansi:-std=c89} %(cpp_options) %(cc1_options)}}}}\
+               cc1 -lang-c %{ansi:-std=c89} %(cpp_unique_options) %(cc1_options)}}}}\
         %{!fsyntax-only:%(invoke_as)}}}}", 0},
   {"-",
    "%{!E:%e-E required when input is from standard input}\
@@ -972,7 +974,6 @@ static const struct option_map option_map[] =
    {"--use-version", "-V", "a"},
    {"--user-dependencies", "-MM", 0},
    {"--verbose", "-v", 0},
-   {"--version", "-dumpversion", 0},
    {"--warn-", "-W", "*j"},
    {"--write-dependencies", "-MD", 0},
    {"--write-user-dependencies", "-MMD", 0},
@@ -1358,6 +1359,7 @@ static struct spec_list static_specs[] =
   INIT_STATIC_SPEC ("invoke_as",               &invoke_as),
   INIT_STATIC_SPEC ("cpp",                     &cpp_spec),
   INIT_STATIC_SPEC ("cpp_options",             &cpp_options),
+  INIT_STATIC_SPEC ("cpp_unique_options",      &cpp_unique_options),
   INIT_STATIC_SPEC ("trad_capable_cpp",                &trad_capable_cpp),
   INIT_STATIC_SPEC ("cc1",                     &cc1_spec),
   INIT_STATIC_SPEC ("cc1_options",             &cc1_options),
@@ -1368,7 +1370,6 @@ static struct spec_list static_specs[] =
   INIT_STATIC_SPEC ("libgcc",                  &libgcc_spec),
   INIT_STATIC_SPEC ("startfile",               &startfile_spec),
   INIT_STATIC_SPEC ("switches_need_spaces",    &switches_need_spaces),
-  INIT_STATIC_SPEC ("signed_char",             &signed_char_spec),
   INIT_STATIC_SPEC ("predefines",              &cpp_predefines),
   INIT_STATIC_SPEC ("cross_compile",           &cross_compile),
   INIT_STATIC_SPEC ("version",                 &compiler_version),
@@ -1406,28 +1407,36 @@ static struct spec_list *specs = (struct spec_list *) 0;
 
 #ifdef ENABLE_SHARED_LIBGCC
 static void
-init_gcc_specs (obstack, shared_name, static_name)
+init_gcc_specs (obstack, shared_name, static_name, eh_name)
      struct obstack *obstack;
      const char *shared_name;
      const char *static_name;
+     const char *eh_name;
 {
   char buffer[128];
+  const char *p;
 
   /* If we see -shared-libgcc, then use the shared version.  */
   sprintf (buffer, "%%{shared-libgcc:%s %s}", shared_name, static_name);
   obstack_grow (obstack, buffer, strlen (buffer));
   /* If we see -static-libgcc, then use the static version.  */
-  sprintf (buffer, "%%{static-libgcc:%s}", static_name);
+  sprintf (buffer, "%%{static-libgcc:%s %s}", static_name, eh_name);
   obstack_grow (obstack, buffer, strlen (buffer));
-  /* Otherwise, if we see -shared, then use the shared version.  */
-  sprintf (buffer,
-          "%%{!shared-libgcc:%%{!static-libgcc:%%{shared:%s %s}}}", 
-          shared_name, static_name);
+  /* Otherwise, if we see -shared, then use the shared version
+     if using EH registration routines or static version without
+     exception handling routines otherwise.  */
+  p = "%{!shared-libgcc:%{!static-libgcc:%{shared:";
+  obstack_grow (obstack, p, strlen (p));
+#ifdef LINK_EH_SPEC
+  sprintf (buffer, "%s}}}", static_name);
+#else
+  sprintf (buffer, "%s}}}", shared_name);
+#endif
   obstack_grow (obstack, buffer, strlen (buffer));
   /* Otherwise, use the static version.  */
   sprintf (buffer, 
-          "%%{!shared-libgcc:%%{!static-libgcc:%%{!shared:%s}}}", 
-          static_name);
+          "%%{!shared-libgcc:%%{!static-libgcc:%%{!shared:%s %s}}}", 
+          static_name, eh_name);
   obstack_grow (obstack, buffer, strlen (buffer));
 }
 #endif /* ENABLE_SHARED_LIBGCC */
@@ -1445,7 +1454,7 @@ init_spec ()
     return;                    /* Already initialized.  */
 
   if (verbose_flag)
-    notice ("Using builtin specs.\n");
+    notice ("Using built-in specs.\n");
 
 #ifdef EXTRA_SPECS
   extra_specs = (struct spec_list *)
@@ -1515,7 +1524,8 @@ init_spec ()
                            "-lgcc_s%M"
 #endif
                            ,
-                           "-lgcc");
+                           "-lgcc",
+                           "-lgcc_eh");
            p += 5;
            in_sep = 0;
          }
@@ -1530,7 +1540,8 @@ init_spec ()
                            "-lgcc_s%M"
 #endif
                            ,
-                           "libgcc.a%s");
+                           "libgcc.a%s",
+                           "libgcc_eh.a%s");
            p += 10;
            in_sep = 0;
          }
@@ -1555,6 +1566,12 @@ init_spec ()
     asm_spec = obstack_finish (&obstack);
   }
 #endif
+#ifdef LINK_EH_SPEC
+  /* Prepend LINK_EH_SPEC to whatever link_spec we had before.  */
+  obstack_grow (&obstack, LINK_EH_SPEC, sizeof(LINK_EH_SPEC) - 1);
+  obstack_grow0 (&obstack, link_spec, strlen (link_spec));
+  link_spec = obstack_finish (&obstack);
+#endif
 
   specs = sl;
 }
@@ -1755,7 +1772,7 @@ load_specs (filename)
 
    A suffix which starts with `*' is a definition for
    one of the machine-specific sub-specs.  The "suffix" should be
-   *asm, *cc1, *cpp, *link, *startfile, *signed_char, etc.
+   *asm, *cc1, *cpp, *link, *startfile, etc.
    The corresponding spec is stored in asm_spec, etc.,
    rather than in the `compilers' vector.
 
@@ -2723,8 +2740,24 @@ execute ()
        {
          const char *const *j;
 
-         for (j = commands[i].argv; *j; j++)
-           fprintf (stderr, " %s", *j);
+         if (verbose_only_flag)
+           {
+             for (j = commands[i].argv; *j; j++)
+               {
+                 const char *p;
+                 fprintf (stderr, " \"");
+                 for (p = *j; *p; ++p)
+                   {
+                     if (*p == '"' || *p == '\\' || *p == '$')
+                       fputc ('\\', stderr);
+                     fputc (*p, stderr);
+                   }
+                 fputc ('"', stderr);
+               }
+           }
+         else
+           for (j = commands[i].argv; *j; j++)
+             fprintf (stderr, " %s", *j);
 
          /* Print a pipe symbol after all but the last command.  */
          if (i + 1 != n_commands)
@@ -2732,6 +2765,8 @@ execute ()
          fprintf (stderr, "\n");
        }
       fflush (stderr);
+      if (verbose_only_flag != 0)
+        return 0;
 #ifdef DEBUG
       notice ("\nGo ahead? (y or n) ");
       fflush (stderr);
@@ -2924,12 +2959,14 @@ static int *warn_std_ptr = 0;
 #if defined(HAVE_TARGET_OBJECT_SUFFIX) || defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
 
 /* Convert NAME to a new name if it is the standard suffix.  DO_EXE
-   is true if we should look for an executable suffix as well.  */
+   is true if we should look for an executable suffix.  DO_OBJ
+   is true if we should look for an object suffix.  */
 
 static const char *
-convert_filename (name, do_exe)
+convert_filename (name, do_exe, do_obj)
      const char *name;
      int do_exe ATTRIBUTE_UNUSED;
+     int do_obj ATTRIBUTE_UNUSED;
 {
 #if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
   int i;
@@ -2943,7 +2980,7 @@ convert_filename (name, do_exe)
 
 #ifdef HAVE_TARGET_OBJECT_SUFFIX
   /* Convert x.o to x.obj if TARGET_OBJECT_SUFFIX is ".obj".  */
-  if (len > 2
+  if (do_obj && len > 2
       && name[len - 2] == '.'
       && name[len - 1] == 'o')
     {
@@ -3007,12 +3044,13 @@ display_help ()
   fputs (_("  -save-temps              Do not delete intermediate files\n"), stdout);
   fputs (_("  -pipe                    Use pipes rather than intermediate files\n"), stdout);
   fputs (_("  -time                    Time the execution of each subprocess\n"), stdout);
-  fputs (_("  -specs=<file>            Override builtin specs with the contents of <file>\n"), stdout);
+  fputs (_("  -specs=<file>            Override built-in specs with the contents of <file>\n"), stdout);
   fputs (_("  -std=<standard>          Assume that the input sources are for <standard>\n"), stdout);
   fputs (_("  -B <directory>           Add <directory> to the compiler's search paths\n"), stdout);
   fputs (_("  -b <machine>             Run gcc for target <machine>, if installed\n"), stdout);
   fputs (_("  -V <version>             Run gcc version number <version>, if installed\n"), stdout);
   fputs (_("  -v                       Display the programs invoked by the compiler\n"), stdout);
+  fputs (_("  -###                     Like -v but options quoted and commands not executed\n"), stdout);
   fputs (_("  -E                       Preprocess only; do not compile, assemble or link\n"), stdout);
   fputs (_("  -S                       Compile only; do not assemble or link\n"), stdout);
   fputs (_("  -c                       Compile and assemble, but do not link\n"), stdout);
@@ -3020,7 +3058,7 @@ display_help ()
   fputs (_("\
   -x <language>            Specify the language of the following input files\n\
                            Permissable languages include: c c++ assembler none\n\
-                           'none' means revert to the default behaviour of\n\
+                           'none' means revert to the default behavior of\n\
                            guessing the language based on the file's extension\n\
 "), stdout);
 
@@ -3301,6 +3339,17 @@ process_command (argc, argv)
          printf ("%s\n", spec_machine);
          exit (0);
        }
+      else if (strcmp (argv[i], "-fversion") == 0)
+       {
+         /* translate_options () has turned --version into -fversion.  */
+         printf (_("%s (GCC) %s\n"), programname, version_string);
+         fputs (_("Copyright (C) 2002 Free Software Foundation, Inc.\n"),
+                stdout);
+         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"),
+                stdout);
+         exit (0);
+       }
       else if (strcmp (argv[i], "-fhelp") == 0)
        {
          /* translate_options () has turned --help into -fhelp.  */
@@ -3310,6 +3359,9 @@ process_command (argc, argv)
          n_infiles++;
          n_switches++;
 
+         /* CPP driver cannot obtain switch from cc1_options.  */
+         if (is_cpp_driver)
+           add_preprocessor_option ("--help", 6);
          add_assembler_option ("--help", 6);
          add_linker_option ("--help", 6);
        }
@@ -3322,6 +3374,9 @@ process_command (argc, argv)
           n_infiles++;
           n_switches++;
 
+         /* CPP driver cannot obtain switch from cc1_options.  */
+         if (is_cpp_driver)
+           add_preprocessor_option ("--target-help", 13);
           add_assembler_option ("--target-help", 13);
           add_linker_option ("--target-help", 13);
         }
@@ -3441,6 +3496,15 @@ process_command (argc, argv)
        }
       else if (strcmp (argv[i], "-time") == 0)
        report_times = 1;
+      else if (strcmp (argv[i], "-###") == 0)
+       {
+         /* This is similar to -v except that there is no execution
+            of the commands and the echoed arguments are quoted.  It
+            is intended for use in shell scripts to capture the
+            driver-generated command line.  */
+         verbose_only_flag++;
+         verbose_flag++;
+       }
       else if (argv[i][0] == '-' && argv[i][1] != 0)
        {
          const char *p = &argv[i][1];
@@ -3618,9 +3682,9 @@ process_command (argc, argv)
 #endif
 #if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) || defined(HAVE_TARGET_OBJECT_SUFFIX)
              if (p[1] == 0)
-               argv[i + 1] = convert_filename (argv[i + 1], ! have_c);
+               argv[i + 1] = convert_filename (argv[i + 1], ! have_c, 0);
              else
-               argv[i] = convert_filename (argv[i], ! have_c);
+               argv[i] = convert_filename (argv[i], ! have_c, 0);
 #endif
              goto normal_switch;
 
@@ -3792,41 +3856,10 @@ process_command (argc, argv)
        ;
       else if (! strcmp (argv[i], "-print-multi-directory"))
        ;
-      else if (strcmp (argv[i], "-ftarget-help") == 0)
-        {
-           /* Create a dummy input file, so that we can pass --target-help on to
-              the various sub-processes.  */
-           infiles[n_infiles].language = "c";
-           infiles[n_infiles++].name   = "target-dummy";
-
-           /* Preserve the --target-help switch so that it can be caught by
-              the cc1 spec string.  */
-           switches[n_switches].part1     = "--target-help";
-           switches[n_switches].args      = 0;
-           switches[n_switches].live_cond = SWITCH_OK;
-           switches[n_switches].validated = 0;
-
-           n_switches++;
-        }
-      else if (strcmp (argv[i], "-fhelp") == 0)
-       {
-         if (verbose_flag)
-           {
-             /* Create a dummy input file, so that we can pass --help on to
-                the various sub-processes.  */
-             infiles[n_infiles].language = "c";
-             infiles[n_infiles++].name   = "help-dummy";
-
-             /* Preserve the --help switch so that it can be caught by the
-                cc1 spec string.  */
-             switches[n_switches].part1     = "--help";
-             switches[n_switches].args      = 0;
-             switches[n_switches].live_cond = SWITCH_OK;
-             switches[n_switches].validated = 0;
-
-             n_switches++;
-           }
-       }
+      else if (! strcmp (argv[i], "-ftarget-help"))
+       ;
+      else if (! strcmp (argv[i], "-fhelp"))
+       ;
       else if (argv[i][0] == '+' && argv[i][1] == 'e')
        {
          /* Compensate for the +e options to the C++ front-end;
@@ -3890,6 +3923,8 @@ process_command (argc, argv)
          else if (report_times)
            error ("warning: -pipe ignored because -time specified");
        }
+      else if (strcmp (argv[i], "-###") == 0)
+       ;
       else if (argv[i][0] == '-' && argv[i][1] != 0)
        {
          const char *p = &argv[i][1];
@@ -3970,7 +4005,7 @@ process_command (argc, argv)
       else
        {
 #ifdef HAVE_TARGET_OBJECT_SUFFIX
-         argv[i] = convert_filename (argv[i], 0);
+         argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK));
 #endif
 
          if (strcmp (argv[i], "-") != 0 && access (argv[i], F_OK) < 0)
@@ -3989,6 +4024,37 @@ process_command (argc, argv)
   if (n_infiles == last_language_n_infiles && spec_lang != 0)
     error ("warning: `-x %s' after last input file has no effect", spec_lang);
 
+  /* Ensure we only invoke each subprocess once.  */
+  if (target_help_flag || print_help_list)
+    {
+      n_infiles = 1;
+
+      /* Create a dummy input file, so that we can pass --target-help on to
+        the various sub-processes.  */
+      infiles[0].language = "c";
+      infiles[0].name   = "help-dummy";
+
+      if (target_help_flag)
+       {
+         switches[n_switches].part1     = "--target-help";
+         switches[n_switches].args      = 0;
+         switches[n_switches].live_cond = SWITCH_OK;
+         switches[n_switches].validated = 0;
+
+         n_switches++;
+       }
+
+      if (print_help_list)
+       {
+         switches[n_switches].part1     = "--help";
+         switches[n_switches].args      = 0;
+         switches[n_switches].live_cond = SWITCH_OK;
+         switches[n_switches].validated = 0;
+
+         n_switches++;
+       }
+    }
+
   switches[n_switches].part1 = 0;
   infiles[n_infiles].name = 0;
 }
@@ -4066,6 +4132,8 @@ static int basename_length;
 static int suffixed_basename_length;
 static const char *input_basename;
 static const char *input_suffix;
+static struct stat input_stat;
+static int input_stat_set;
 
 /* The compiler used to process the current input file.  */
 static struct compiler *input_file_compiler;
@@ -4431,12 +4499,6 @@ do_spec_1 (spec, inswitch, soft_matched_part)
          case 'g':
          case 'u':
          case 'U':
-           if (save_temps_flag)
-             {
-               obstack_grow (&obstack, input_basename, basename_length);
-               delete_this_arg = 0;
-             }
-           else
              {
                struct temp_name *t;
                int suffix_length;
@@ -4465,6 +4527,54 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                      }
                    suffix_length += strlen (TARGET_OBJECT_SUFFIX);
                  }
+               
+               /* If the 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)
+                 {
+                   temp_filename_length = basename_length + suffix_length;
+                   temp_filename = alloca (temp_filename_length + 1);
+                   strncpy ((char *) temp_filename, input_basename, basename_length);
+                   strncpy ((char *) temp_filename + basename_length, suffix,
+                            suffix_length);
+                   *((char *) temp_filename + temp_filename_length) = '\0';
+                   if (strcmp (temp_filename, input_filename) != 0)
+                     {
+                       struct stat st_temp;
+                       
+                       /* Note, set_input() resets input_stat_set to 0.  */
+                       if (input_stat_set == 0)
+                         {
+                           input_stat_set = stat (input_filename, &input_stat);
+                           if (input_stat_set >= 0)
+                             input_stat_set = 1;
+                         }
+                         
+                       /* If we have the stat for the input_filename
+                          and we can do the stat for the temp_filename
+                          then the they could still refer to the same
+                          file if st_dev/st_ino's are the same.  */
+                       
+                       if (input_stat_set != 1
+                           || stat (temp_filename, &st_temp) < 0
+                           || input_stat.st_dev != st_temp.st_dev
+                           || input_stat.st_ino != st_temp.st_ino)
+                         {
+                           temp_filename = save_string (temp_filename,
+                                                        temp_filename_length + 1);
+                           obstack_grow (&obstack, temp_filename,
+                                                   temp_filename_length);
+                           arg_going = 1;
+                           break;
+                         }
+                     }
+                 }
 
                /* See if we already have an association of %g/%u/%U and
                   suffix.  */
@@ -4660,12 +4770,6 @@ do_spec_1 (spec, inswitch, soft_matched_part)
              return value;
            break;
 
-         case 'c':
-           value = do_spec_1 (signed_char_spec, 0, NULL);
-           if (value != 0)
-             return value;
-           break;
-
          case 'C':
            {
              const char *const spec
@@ -4919,7 +5023,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
              /* Catch the case where a spec string contains something like
                 '%{foo:%*}'.  ie there is no * in the pattern on the left
                 hand side of the :.  */
-             error ("spec failure: '%%*' has not been initialised by pattern match");
+             error ("spec failure: '%%*' has not been initialized by pattern match");
            break;
 
            /* Process a string found as the value of a spec given by name.
@@ -5071,7 +5175,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
            break;
 
          default:
-           error ("spec failure: unrecognised spec option '%c'", c);
+           error ("spec failure: unrecognized spec option '%c'", c);
            break;
          }
        break;
@@ -5607,6 +5711,11 @@ set_input (filename)
     }
   else
     input_suffix = "";
+  
+  /* If a spec for 'g', 'u', or 'U' is seen with -save-temps then
+     we will need to do a stat on the input_filename.  The
+     INPUT_STAT_SET signals that the stat is needed.  */
+  input_stat_set = 0;
 }
 \f
 /* On fatal signals, delete all the temporary files.  */
@@ -5896,7 +6005,7 @@ main (argc, argv)
 
   if (target_help_flag)
    {
-      /* Print if any target specific options.*/
+      /* Print if any target specific options.  */
 
       /* We do not exit here. Instead we have created a fake input file
          called 'target-dummy' which needs to be compiled, and we pass this