OSDN Git Service

./:
[pf3gnuchains/gcc-fork.git] / gcc / toplev.c
index 36b24d7..4836238 100644 (file)
@@ -1,6 +1,6 @@
 /* Top level of GCC compilers (cc1, cc1plus, etc.)
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -66,6 +66,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic.h"
 #include "params.h"
 #include "reload.h"
+#include "ira.h"
 #include "dwarf2asm.h"
 #include "integrate.h"
 #include "real.h"
@@ -82,6 +83,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "alloc-pool.h"
 #include "tree-mudflap.h"
 #include "tree-pass.h"
+#include "gimple.h"
+#include "tree-ssa-alias.h"
+#include "plugin.h"
 
 #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
 #include "dwarf2out.h"
@@ -202,11 +206,6 @@ tree current_function_decl;
    if none.  */
 const char * current_function_func_begin_label;
 
-/* Temporarily suppress certain warnings.
-   This is set while reading code from a system header file.  */
-
-int in_system_header = 0;
-
 /* Nonzero means to collect statistics which might be expensive
    and to print them when we are done.  */
 int flag_detailed_statistics = 0;
@@ -249,11 +248,6 @@ int flag_pcc_struct_return = DEFAULT_PCC_STRUCT_RETURN;
 
 int flag_complex_method = 1;
 
-/* Nonzero means that we don't want inlining by virtue of -fno-inline,
-   not just because the tree inliner turned us off.  */
-
-int flag_really_no_inline = 2;
-
 /* Nonzero means we should be saving declaration info into a .X file.  */
 
 int flag_gen_aux_info = 0;
@@ -279,6 +273,21 @@ int flag_next_runtime = 0;
 
 enum tls_model flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC;
 
+/* Set the default region and algorithm for the integrated register
+   allocator.  */
+
+enum ira_algorithm flag_ira_algorithm = IRA_ALGORITHM_CB;
+enum ira_region flag_ira_region = IRA_REGION_MIXED;
+
+/* Set the default value for -fira-verbose.  */
+
+unsigned int flag_ira_verbose = 5;
+
+/* Set the default for excess precision.  */
+
+enum excess_precision flag_excess_precision_cmdline = EXCESS_PRECISION_DEFAULT;
+enum excess_precision flag_excess_precision = EXCESS_PRECISION_DEFAULT;
+
 /* Nonzero means change certain warnings into errors.
    Usually these are warnings about failure to conform to some standard.  */
 
@@ -315,6 +324,9 @@ rtx stack_limit_rtx;
    to optimize, debug_info_level and debug_hooks in process_options ().  */
 int flag_var_tracking = AUTODETECT_VALUE;
 
+/* Type of stack check.  */
+enum stack_check_type flag_stack_check = NO_STACK_CHECK;
+
 /* True if the user has tagged the function with the 'section'
    attribute.  */
 
@@ -415,9 +427,11 @@ announce_function (tree decl)
   if (!quiet_flag)
     {
       if (rtl_dump_and_exit)
-       fprintf (stderr, "%s ", IDENTIFIER_POINTER (DECL_NAME (decl)));
+       fprintf (stderr, "%s ",
+                identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (decl))));
       else
-       fprintf (stderr, " %s", lang_hooks.decl_printable_name (decl, 2));
+       fprintf (stderr, " %s",
+                identifier_to_locale (lang_hooks.decl_printable_name (decl, 2)));
       fflush (stderr);
       pp_needs_newline (global_dc->printer) = true;
       diagnostic_set_last_function (global_dc, (diagnostic_info *) NULL);
@@ -518,11 +532,11 @@ read_integral_parameter (const char *p, const char *pname, const int  defval)
   return atoi (p);
 }
 
-/* When compiling with a recent enough GCC, we use the GNU C "extern inline"
-   for floor_log2 and exact_log2; see toplev.h.  That construct, however,
-   conflicts with the ISO C++ One Definition Rule.   */
+#if GCC_VERSION < 3004
 
-#if GCC_VERSION < 3004 || !defined (__cplusplus)
+/* The functions floor_log2 and exact_log2 are defined as inline
+   functions in toplev.h if GCC_VERSION >= 3004.  The definitions here
+   are used for older versions of gcc.  */
 
 /* Given X, an unsigned number, return the largest int Y such that 2**Y <= X.
    If X is 0, return -1.  */
@@ -535,9 +549,6 @@ floor_log2 (unsigned HOST_WIDE_INT x)
   if (x == 0)
     return -1;
 
-#ifdef CLZ_HWI
-  t = HOST_BITS_PER_WIDE_INT - 1 - (int) CLZ_HWI (x);
-#else
   if (HOST_BITS_PER_WIDE_INT > 64)
     if (x >= (unsigned HOST_WIDE_INT) 1 << (t + 64))
       t += 64;
@@ -554,7 +565,6 @@ floor_log2 (unsigned HOST_WIDE_INT x)
     t += 2;
   if (x >= ((unsigned HOST_WIDE_INT) 1) << (t + 1))
     t += 1;
-#endif
 
   return t;
 }
@@ -567,14 +577,10 @@ exact_log2 (unsigned HOST_WIDE_INT x)
 {
   if (x != (x & -x))
     return -1;
-#ifdef CTZ_HWI
-  return x ? CTZ_HWI (x) : -1;
-#else
   return floor_log2 (x);
-#endif
 }
 
-#endif /*  GCC_VERSION < 3004 || !defined (__cplusplus)  */
+#endif /* GCC_VERSION < 3004 */
 
 /* Handler for fatal signals, such as SIGSEGV.  These are transformed
    into ICE messages, which is much more user friendly.  In case the
@@ -830,7 +836,7 @@ check_global_declaration_1 (tree decl)
          || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))
     {
       if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
-       pedwarn ("%q+F used but never defined", decl);
+       pedwarn (input_location, 0, "%q+F used but never defined", decl);
       else
        warning (OPT_Wunused_function, "%q+F declared %<static%> but never defined", decl);
       /* This symbol is effectively an "extern" declaration now.  */
@@ -894,30 +900,58 @@ emit_debug_global_declarations (tree *vec, int len)
 
 /* Warn about a use of an identifier which was marked deprecated.  */
 void
-warn_deprecated_use (tree node)
+warn_deprecated_use (tree node, tree attr)
 {
+  const char *msg;
+
   if (node == 0 || !warn_deprecated_decl)
     return;
 
+  if (!attr)
+    {
+      if (DECL_P (node))
+       attr = DECL_ATTRIBUTES (node);
+      else if (TYPE_P (node))
+       {
+         tree decl = TYPE_STUB_DECL (node);
+         if (decl)
+           attr = lookup_attribute ("deprecated",
+                                    TYPE_ATTRIBUTES (TREE_TYPE (decl)));
+       }
+    }
+
+  if (attr)
+    attr = lookup_attribute ("deprecated", attr);
+
+  if (attr)
+    msg = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)));
+  else
+    msg = NULL;
+
   if (DECL_P (node))
     {
       expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (node));
-      warning (OPT_Wdeprecated_declarations,
-              "%qD is deprecated (declared at %s:%d)",
-              node, xloc.file, xloc.line);
+      if (msg)
+       warning (OPT_Wdeprecated_declarations,
+                "%qD is deprecated (declared at %s:%d): %s",
+                node, xloc.file, xloc.line, msg);
+      else
+       warning (OPT_Wdeprecated_declarations,
+                "%qD is deprecated (declared at %s:%d)",
+                node, xloc.file, xloc.line);
     }
   else if (TYPE_P (node))
     {
-      const char *what = NULL;
+      tree what = NULL_TREE;
       tree decl = TYPE_STUB_DECL (node);
 
       if (TYPE_NAME (node))
        {
          if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE)
-           what = IDENTIFIER_POINTER (TYPE_NAME (node));
+           what = TYPE_NAME (node);
          else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
                   && DECL_NAME (TYPE_NAME (node)))
-           what = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node)));
+           what = DECL_NAME (TYPE_NAME (node));
        }
 
       if (decl)
@@ -925,20 +959,46 @@ warn_deprecated_use (tree node)
          expanded_location xloc
            = expand_location (DECL_SOURCE_LOCATION (decl));
          if (what)
-           warning (OPT_Wdeprecated_declarations,
-                    "%qs is deprecated (declared at %s:%d)", what,
-                    xloc.file, xloc.line);
+           {
+             if (msg)
+               warning (OPT_Wdeprecated_declarations,
+                        "%qE is deprecated (declared at %s:%d): %s",
+                        what, xloc.file, xloc.line, msg);
+             else
+               warning (OPT_Wdeprecated_declarations,
+                        "%qE is deprecated (declared at %s:%d)", what,
+                        xloc.file, xloc.line);
+           }
          else
-           warning (OPT_Wdeprecated_declarations,
-                    "type is deprecated (declared at %s:%d)",
-                    xloc.file, xloc.line);
+           {
+             if (msg)
+               warning (OPT_Wdeprecated_declarations,
+                        "type is deprecated (declared at %s:%d): %s",
+                        xloc.file, xloc.line, msg);
+             else
+               warning (OPT_Wdeprecated_declarations,
+                        "type is deprecated (declared at %s:%d)",
+                        xloc.file, xloc.line);
+           }
        }
       else
        {
          if (what)
-           warning (OPT_Wdeprecated_declarations, "%qs is deprecated", what);
+           {
+             if (msg)
+               warning (OPT_Wdeprecated_declarations, "%qE is deprecated: %s",
+                        what, msg);
+             else
+               warning (OPT_Wdeprecated_declarations, "%qE is deprecated", what);
+           }
          else
-           warning (OPT_Wdeprecated_declarations, "type is deprecated");
+           {
+             if (msg)
+               warning (OPT_Wdeprecated_declarations, "type is deprecated: %s",
+                        msg);
+             else
+               warning (OPT_Wdeprecated_declarations, "type is deprecated");
+           }
        }
     }
 }
@@ -951,9 +1011,12 @@ compile_file (void)
 {
   /* Initialize yet another pass.  */
 
+  ggc_protect_identifiers = true;
+
   init_cgraph ();
   init_final (main_input_filename);
   coverage_init (aux_base_name);
+  statistics_init ();
 
   timevar_push (TV_PARSE);
 
@@ -968,6 +1031,8 @@ compile_file (void)
   if (flag_syntax_only)
     return;
 
+  ggc_protect_identifiers = false;
+
   lang_hooks.decls.final_write_globals ();
 
   if (errorcount || sorrycount)
@@ -976,11 +1041,6 @@ compile_file (void)
   varpool_assemble_pending_decls ();
   finish_aliases_2 ();
 
-  /* This must occur after the loop to output deferred functions.
-     Else the coverage initializer would not be emitted if all the
-     functions in this compilation unit were deferred.  */
-  coverage_finish ();
-
   /* Likewise for mudflap static object registrations.  */
   if (flag_mudflap)
     mudflap_finish_file ();
@@ -1067,14 +1127,16 @@ decode_d_option (const char *arg)
       case 'I':
       case 'M':
       case 'N':
+      case 'U':
        break;
       case 'H':
        setup_core_dumping();
        break;
-
       case 'a':
+       enable_rtl_dump_file ();
+       break;
+
       default:
-       if (!enable_rtl_dump_file (c))
          warning (0, "unrecognized gcc debugging option: %c", c);
        break;
       }
@@ -1100,8 +1162,13 @@ print_version (FILE *file, const char *indent)
     N_("%s%s%s %sversion %s (%s) compiled by CC, ")
 #endif
     ;
+#ifdef HAVE_mpc
+  static const char fmt2[] =
+    N_("GMP version %s, MPFR version %s, MPC version %s\n");
+#else
   static const char fmt2[] =
-    N_("GMP version %s, MPFR version %s.\n");
+    N_("GMP version %s, MPFR version %s\n");
+#endif
   static const char fmt3[] =
     N_("%s%swarning: %s header version %s differs from library version %s.\n");
   static const char fmt4[] =
@@ -1116,10 +1183,14 @@ print_version (FILE *file, const char *indent)
           indent, __VERSION__);
 
   /* We need to stringify the GMP macro values.  Ugh, gmp_version has
-     two string formats, "i.j.k" and "i.j" when k is zero.  */
+     two string formats, "i.j.k" and "i.j" when k is zero.  As of
+     gmp-4.3.0, GMP always uses the 3 number format.  */
 #define GCC_GMP_STRINGIFY_VERSION3(X) #X
 #define GCC_GMP_STRINGIFY_VERSION2(X) GCC_GMP_STRINGIFY_VERSION3(X)
-#if __GNU_MP_VERSION_PATCHLEVEL == 0
+#define GCC_GMP_VERSION_NUM(X,Y,Z) (((X) << 16L) | ((Y) << 8) | (Z))
+#define GCC_GMP_VERSION \
+  GCC_GMP_VERSION_NUM(__GNU_MP_VERSION, __GNU_MP_VERSION_MINOR, __GNU_MP_VERSION_PATCHLEVEL)
+#if GCC_GMP_VERSION < GCC_GMP_VERSION_NUM(4,3,0) && __GNU_MP_VERSION_PATCHLEVEL == 0
 #define GCC_GMP_STRINGIFY_VERSION GCC_GMP_STRINGIFY_VERSION2(__GNU_MP_VERSION) "." \
   GCC_GMP_STRINGIFY_VERSION2(__GNU_MP_VERSION_MINOR)
 #else
@@ -1129,7 +1200,11 @@ print_version (FILE *file, const char *indent)
 #endif
   fprintf (file,
           file == stderr ? _(fmt2) : fmt2,
-          GCC_GMP_STRINGIFY_VERSION, MPFR_VERSION_STRING);
+          GCC_GMP_STRINGIFY_VERSION, MPFR_VERSION_STRING
+#ifdef HAVE_mpc
+          , MPC_VERSION_STRING
+#endif
+          );
   if (strcmp (GCC_GMP_STRINGIFY_VERSION, gmp_version))
     fprintf (file,
             file == stderr ? _(fmt3) : fmt3,
@@ -1140,10 +1215,19 @@ print_version (FILE *file, const char *indent)
             file == stderr ? _(fmt3) : fmt3,
             indent, *indent != 0 ? " " : "",
             "MPFR", MPFR_VERSION_STRING, mpfr_get_version ());
+#ifdef HAVE_mpc
+  if (strcmp (MPC_VERSION_STRING, mpc_get_version ()))
+    fprintf (file,
+            file == stderr ? _(fmt3) : fmt3,
+            indent, *indent != 0 ? " " : "",
+            "MPC", MPC_VERSION_STRING, mpc_get_version ());
+#endif
   fprintf (file,
           file == stderr ? _(fmt4) : fmt4,
           indent, *indent != 0 ? " " : "",
           PARAM_VALUE (GGC_MIN_EXPAND), PARAM_VALUE (GGC_MIN_HEAPSIZE));
+
+  print_plugins_versions (file, indent);
 }
 
 #ifdef ASM_COMMENT_START
@@ -1349,7 +1433,7 @@ init_asm_output (const char *name)
                                                   NULL);
            }
          else
-           inform ("-frecord-gcc-switches is not supported by the current target");
+           inform (input_location, "-frecord-gcc-switches is not supported by the current target");
        }
 
 #ifdef ASM_COMMENT_START
@@ -1487,6 +1571,15 @@ default_tree_printer (pretty_printer * pp, text_info *text, const char *spec,
 
   switch (*spec)
     {
+    case 'E':
+      t = va_arg (*text->args_ptr, tree);
+      if (TREE_CODE (t) == IDENTIFIER_NODE)
+       {
+         pp_identifier (pp, IDENTIFIER_POINTER (t));
+         return true;
+       }
+      break;
+
     case 'D':
       t = va_arg (*text->args_ptr, tree);
       if (DECL_DEBUG_EXPR_IS_FROM (t) && DECL_DEBUG_EXPR (t))
@@ -1508,8 +1601,8 @@ default_tree_printer (pretty_printer * pp, text_info *text, const char *spec,
   if (DECL_P (t))
     {
       const char *n = DECL_NAME (t)
-        ? lang_hooks.decl_printable_name (t, 2)
-        : "<anonymous>";
+        ? identifier_to_locale (lang_hooks.decl_printable_name (t, 2))
+        : _("<anonymous>");
       pp_string (pp, n);
     }
   else
@@ -1596,6 +1689,7 @@ general_init (const char *argv0)
   /* This must be done after add_params but before argument processing.  */
   init_ggc_heuristics();
   init_optimization_passes ();
+  statistics_early_init ();
 }
 
 /* Return true if the current target supports -fsection-anchors.  */
@@ -1645,6 +1739,23 @@ process_options (void)
      This can happen with incorrect pre-processed input. */
   debug_hooks = &do_nothing_debug_hooks;
 
+  /* This replaces set_Wunused.  */
+  if (warn_unused_function == -1)
+    warn_unused_function = warn_unused;
+  if (warn_unused_label == -1)
+    warn_unused_label = warn_unused;
+  /* Wunused-parameter is enabled if both -Wunused -Wextra are enabled.  */
+  if (warn_unused_parameter == -1)
+    warn_unused_parameter = (warn_unused && extra_warnings);
+  if (warn_unused_variable == -1)
+    warn_unused_variable = warn_unused;
+  if (warn_unused_value == -1)
+    warn_unused_value = warn_unused;
+
+  /* This replaces set_Wextra.  */
+  if (warn_uninitialized == -1)
+    warn_uninitialized = extra_warnings;
+
   /* Allow the front end to perform consistency checks and do further
      initialization based on the command line options.  This hook also
      sets the original filename if appropriate (e.g. foo.i -> foo.c)
@@ -1679,6 +1790,15 @@ process_options (void)
   else
     aux_base_name = "gccaux";
 
+#ifndef HAVE_cloog
+  if (flag_graphite
+      || flag_loop_block
+      || flag_loop_interchange
+      || flag_loop_strip_mine
+      || flag_graphite_identity)
+    sorry ("Graphite loop optimizations cannot be used");
+#endif
+
   /* Unrolling all loops implies that standard loop unrolling must also
      be done.  */
   if (flag_unroll_all_loops)
@@ -1699,9 +1819,6 @@ process_options (void)
   if (flag_asynchronous_unwind_tables)
     flag_unwind_tables = 1;
 
-  if (!flag_unit_at_a_time)
-    flag_section_anchors = 0;
-
   if (flag_value_profile_transformations)
     flag_profile_values = 1;
 
@@ -1745,6 +1862,31 @@ process_options (void)
       profile_flag = 0;
     }
 
+  if (flag_gtoggle)
+    {
+      if (debug_info_level == DINFO_LEVEL_NONE)
+       debug_info_level = DINFO_LEVEL_NORMAL;
+      else
+       debug_info_level = DINFO_LEVEL_NONE;
+    }
+
+  if (flag_dump_final_insns)
+    {
+      FILE *final_output = fopen (flag_dump_final_insns, "w");
+      if (!final_output)
+       {
+         error ("could not open final insn dump file %qs: %s",
+                flag_dump_final_insns, strerror (errno));
+         flag_dump_final_insns = NULL;
+       }
+      else if (fclose (final_output))
+       {
+         error ("could not close zeroed insn dump file %qs: %s",
+                flag_dump_final_insns, strerror (errno));
+         flag_dump_final_insns = NULL;
+       }
+    }
+
   /* A lot of code assumes write_symbols == NO_DEBUG if the debugging
      level is 0.  */
   if (debug_info_level == DINFO_LEVEL_NONE)
@@ -1894,13 +2036,6 @@ process_options (void)
       flag_prefetch_loop_arrays = 0;
     }
 
-#ifndef OBJECT_FORMAT_ELF
-#ifndef OBJECT_FORMAT_MACHO
-  if (flag_function_sections && write_symbols != NO_DEBUG)
-    warning (0, "-ffunction-sections may affect debugging on some targets");
-#endif
-#endif
-
   /* The presence of IEEE signaling NaNs, implies all math can trap.  */
   if (flag_signaling_nans)
     flag_trapping_math = 1;
@@ -2004,14 +2139,55 @@ backend_init (void)
   save_register_info ();
 
   /* Initialize the target-specific back end pieces.  */
+  ira_init_once ();
   backend_init_target ();
 }
 
+/* Initialize excess precision settings.  */
+static void
+init_excess_precision (void)
+{
+  /* Adjust excess precision handling based on the target options.  If
+     the front end cannot handle it, flag_excess_precision_cmdline
+     will already have been set accordingly in the post_options
+     hook.  */
+  gcc_assert (flag_excess_precision_cmdline != EXCESS_PRECISION_DEFAULT);
+  flag_excess_precision = flag_excess_precision_cmdline;
+  if (flag_unsafe_math_optimizations)
+    flag_excess_precision = EXCESS_PRECISION_FAST;
+  if (flag_excess_precision == EXCESS_PRECISION_STANDARD)
+    {
+      int flt_eval_method = TARGET_FLT_EVAL_METHOD;
+      switch (flt_eval_method)
+       {
+       case -1:
+       case 0:
+         /* Either the target acts unpredictably (-1) or has all the
+            operations required not to have excess precision (0).  */
+         flag_excess_precision = EXCESS_PRECISION_FAST;
+         break;
+       case 1:
+       case 2:
+         /* In these cases, predictable excess precision makes
+            sense.  */
+         break;
+       default:
+         /* Any other implementation-defined FLT_EVAL_METHOD values
+            require the compiler to handle the associated excess
+            precision rules in excess_precision_type.  */
+         gcc_unreachable ();
+       }
+    }
+}
+
 /* Initialize things that are both lang-dependent and target-dependent.
    This function can be called more than once if target parameters change.  */
 static void
 lang_dependent_init_target (void)
 {
+  /* This determines excess precision settings.  */
+  init_excess_precision ();
+
   /* This creates various _DECL nodes, so needs to be called after the
      front end is initialized.  It also depends on the HAVE_xxx macros
      generated from the target machine description.  */
@@ -2024,9 +2200,10 @@ lang_dependent_init_target (void)
   /* Do the target-specific parts of expr initialization.  */
   init_expr_target ();
 
-  /* Although the actions of init_set_costs are language-independent,
-     it uses optabs, so we cannot call it from backend_init.  */
+  /* Although the actions of these functions are language-independent,
+     they use optabs, so we cannot call them from backend_init.  */
   init_set_costs ();
+  ira_init ();
 
   expand_dummy_function_end ();
 }
@@ -2091,11 +2268,15 @@ dump_memory_report (bool final)
   ggc_print_statistics ();
   stringpool_statistics ();
   dump_tree_statistics ();
+  dump_gimple_statistics ();
   dump_rtx_statistics ();
   dump_varray_statistics ();
   dump_alloc_pool_statistics ();
   dump_bitmap_statistics ();
+  dump_vec_loc_statistics ();
   dump_ggc_loc_statistics (final);
+  dump_alias_stats (stderr);
+  dump_pta_stats (stderr);
 }
 
 /* Clean up: close opened files, etc.  */
@@ -2123,8 +2304,11 @@ finalize (void)
        fatal_error ("error closing %s: %m", asm_file_name);
     }
 
+  statistics_fini ();
   finish_optimization_passes ();
 
+  ira_finish_once ();
+
   if (mem_report)
     dump_memory_report (true);
 
@@ -2161,6 +2345,9 @@ do_compile (void)
        compile_file ();
 
       finalize ();
+
+      /* Invoke registered plugin callbacks.  */
+      invoke_plugin_callbacks (PLUGIN_FINISH_UNIT, NULL);
     }
 
   /* Stop timing and print the times.  */
@@ -2175,19 +2362,29 @@ do_compile (void)
    It is not safe to call this function more than once.  */
 
 int
-toplev_main (unsigned int argc, const char **argv)
+toplev_main (int argc, char **argv)
 {
-  save_argv = argv;
+  expandargv (&argc, &argv);
+
+  save_argv = CONST_CAST2 (const char **, char **, argv);
 
   /* Initialization of GCC's environment, and diagnostics.  */
   general_init (argv[0]);
 
   /* Parse the options and do minimal processing; basically just
      enough to default flags appropriately.  */
-  decode_options (argc, argv);
+  decode_options (argc, CONST_CAST2 (const char **, char **, argv));
 
   init_local_tick ();
 
+  initialize_plugins ();
+
+  if (version_flag)
+    print_version (stderr, "");
+
+  if (help_flag)
+    print_plugins_help (stderr, "");
+
   /* Exit early if we can (e.g. -help).  */
   if (!exit_after_options)
     do_compile ();
@@ -2195,6 +2392,10 @@ toplev_main (unsigned int argc, const char **argv)
   if (warningcount || errorcount) 
     print_ignored_options ();
 
+  /* Invoke registered plugin callbacks if any.  */
+  invoke_plugin_callbacks (PLUGIN_FINISH, NULL);
+
+  finalize_plugins ();
   if (errorcount || sorrycount)
     return (FATAL_EXIT_CODE);