OSDN Git Service

* trans-decl.c (gfc_build_qualified_array): Don't skip generation
[pf3gnuchains/gcc-fork.git] / gcc / fortran / trans-decl.c
index 1b47f26..cbfff29 100644 (file)
@@ -1,6 +1,6 @@
 /* Backend function setup
-   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software
-   Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
    Contributed by Paul Brook
 
 This file is part of GCC.
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "debug.h"
 #include "gfortran.h"
+#include "pointer-set.h"
 #include "trans.h"
 #include "trans-types.h"
 #include "trans-array.h"
@@ -60,6 +61,8 @@ static GTY(()) tree current_function_return_label;
 static GTY(()) tree saved_function_decls;
 static GTY(()) tree saved_parent_function_decls;
 
+static struct pointer_set_t *nonlocal_dummy_decl_pset;
+static GTY(()) tree nonlocal_dummy_decls;
 
 /* The namespace of the module we're currently generating.  Only used while
    outputting decls for module variables.  Do not rely on this being set.  */
@@ -83,6 +86,7 @@ tree gfor_fndecl_runtime_error_at;
 tree gfor_fndecl_runtime_warning_at;
 tree gfor_fndecl_os_error;
 tree gfor_fndecl_generate_error;
+tree gfor_fndecl_set_args;
 tree gfor_fndecl_set_fpe;
 tree gfor_fndecl_set_options;
 tree gfor_fndecl_set_convert;
@@ -141,6 +145,8 @@ tree gfor_fndecl_convert_char4_to_char1;
 tree gfor_fndecl_size0;
 tree gfor_fndecl_size1;
 tree gfor_fndecl_iargc;
+tree gfor_fndecl_clz128;
+tree gfor_fndecl_ctz128;
 
 /* Intrinsic functions implemented in Fortran.  */
 tree gfor_fndecl_sc_kind;
@@ -283,7 +289,10 @@ gfc_get_label_decl (gfc_st_label * lp)
 static tree
 gfc_sym_identifier (gfc_symbol * sym)
 {
-  return (get_identifier (sym->name));
+  if (sym->attr.is_main_program && strcmp (sym->name, "main") == 0)
+    return (get_identifier ("MAIN__"));
+  else
+    return (get_identifier (sym->name));
 }
 
 
@@ -704,9 +713,6 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym)
       layout_type (type);
     }
 
-  if (write_symbols == NO_DEBUG)
-    return;
-
   if (TYPE_NAME (type) != NULL_TREE
       && GFC_TYPE_ARRAY_UBOUND (type, sym->as->rank - 1) != NULL_TREE
       && TREE_CODE (GFC_TYPE_ARRAY_UBOUND (type, sym->as->rank - 1)) == VAR_DECL)
@@ -870,6 +876,38 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy)
   return decl;
 }
 
+/* For symbol SYM with GFC_DECL_SAVED_DESCRIPTOR used in contained
+   function add a VAR_DECL to the current function with DECL_VALUE_EXPR
+   pointing to the artificial variable for debug info purposes.  */
+
+static void
+gfc_nonlocal_dummy_array_decl (gfc_symbol *sym)
+{
+  tree decl, dummy;
+
+  if (! nonlocal_dummy_decl_pset)
+    nonlocal_dummy_decl_pset = pointer_set_create ();
+
+  if (pointer_set_insert (nonlocal_dummy_decl_pset, sym->backend_decl))
+    return;
+
+  dummy = GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl);
+  decl = build_decl (VAR_DECL, DECL_NAME (dummy),
+                    TREE_TYPE (sym->backend_decl));
+  DECL_ARTIFICIAL (decl) = 0;
+  TREE_USED (decl) = 1;
+  TREE_PUBLIC (decl) = 0;
+  TREE_STATIC (decl) = 0;
+  DECL_EXTERNAL (decl) = 0;
+  if (DECL_BY_REFERENCE (dummy))
+    DECL_BY_REFERENCE (decl) = 1;
+  DECL_LANG_SPECIFIC (decl) = DECL_LANG_SPECIFIC (sym->backend_decl);
+  SET_DECL_VALUE_EXPR (decl, sym->backend_decl);
+  DECL_HAS_VALUE_EXPR_P (decl) = 1;
+  DECL_CONTEXT (decl) = DECL_CONTEXT (sym->backend_decl);
+  TREE_CHAIN (decl) = nonlocal_dummy_decls;
+  nonlocal_dummy_decls = decl;
+}
 
 /* Return a constant or a variable to use as a string length.  Does not
    add the decl to the current scope.  */
@@ -877,13 +915,12 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy)
 static tree
 gfc_create_string_length (gfc_symbol * sym)
 {
-  tree length;
-
   gcc_assert (sym->ts.cl);
   gfc_conv_const_charlen (sym->ts.cl);
-  
+
   if (sym->ts.cl->backend_decl == NULL_TREE)
     {
+      tree length;
       char name[GFC_MAX_MANGLED_SYMBOL_LEN + 2];
 
       /* Also prefix the mangled name.  */
@@ -895,9 +932,11 @@ gfc_create_string_length (gfc_symbol * sym)
       TREE_USED (length) = 1;
       if (sym->ns->proc_name->tlink != NULL)
        gfc_defer_symbol_init (sym);
+
       sym->ts.cl->backend_decl = length;
     }
 
+  gcc_assert (sym->ts.cl->backend_decl != NULL_TREE);
   return sym->ts.cl->backend_decl;
 }
 
@@ -1009,16 +1048,25 @@ gfc_get_symbol_decl (gfc_symbol * sym)
        {
          gfc_add_assign_aux_vars (sym);
        }
+
+      if (sym->attr.dimension
+         && DECL_LANG_SPECIFIC (sym->backend_decl)
+         && GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl)
+         && DECL_CONTEXT (sym->backend_decl) != current_function_decl)
+       gfc_nonlocal_dummy_array_decl (sym);
+
       return sym->backend_decl;
     }
 
   if (sym->backend_decl)
     return sym->backend_decl;
 
-  /* Catch function declarations.  Only used for actual parameters.  */
+  /* Catch function declarations.  Only used for actual parameters and
+     procedure pointers.  */
   if (sym->attr.flavor == FL_PROCEDURE)
     {
       decl = gfc_get_extern_function_decl (sym);
+      gfc_set_decl_location (decl, &sym->declared_at);
       return decl;
     }
 
@@ -1126,6 +1174,13 @@ gfc_get_symbol_decl (gfc_symbol * sym)
          sym->attr.pointer || sym->attr.allocatable);
     }
 
+  if (!TREE_STATIC (decl)
+      && POINTER_TYPE_P (TREE_TYPE (decl))
+      && !sym->attr.pointer
+      && !sym->attr.allocatable
+      && !sym->attr.proc_pointer)
+    DECL_BY_REFERENCE (decl) = 1;
+
   return decl;
 }
 
@@ -1174,11 +1229,24 @@ get_proc_pointer_decl (gfc_symbol *sym)
       && sym->ns->proc_name->backend_decl == current_function_decl)
       || sym->attr.contained)
     gfc_add_decl_to_function (decl);
-  else
+  else if (sym->ns->proc_name->attr.flavor != FL_MODULE)
     gfc_add_decl_to_parent_function (decl);
 
   sym->backend_decl = decl;
 
+  /* If a variable is USE associated, it's always external.  */
+  if (sym->attr.use_assoc)
+    {
+      DECL_EXTERNAL (decl) = 1;
+      TREE_PUBLIC (decl) = 1;
+    }
+  else if (sym->module && sym->ns->proc_name->attr.flavor == FL_MODULE)
+    {
+      /* This is the declaration of a module variable.  */
+      TREE_PUBLIC (decl) = 1;
+      TREE_STATIC (decl) = 1;
+    }
+
   if (!sym->attr.use_assoc
        && (sym->attr.save != SAVE_NONE || sym->attr.data
              || (sym->value && sym->ns->proc_name->attr.is_main_program)))
@@ -1208,6 +1276,7 @@ gfc_get_extern_function_decl (gfc_symbol * sym)
   char s[GFC_MAX_SYMBOL_LEN + 23]; /* "_gfortran_f2c_specific" and '\0'.  */
   tree name;
   tree mangled_name;
+  gfc_gsymbol *gsym;
 
   if (sym->backend_decl)
     return sym->backend_decl;
@@ -1220,6 +1289,41 @@ gfc_get_extern_function_decl (gfc_symbol * sym)
   if (sym->attr.proc_pointer)
     return get_proc_pointer_decl (sym);
 
+  /* See if this is an external procedure from the same file.  If so,
+     return the backend_decl.  */
+  gsym =  gfc_find_gsymbol (gfc_gsym_root, sym->name);
+
+  if (gfc_option.flag_whole_file
+       && !sym->backend_decl
+       && gsym && gsym->ns
+       && ((gsym->type == GSYM_SUBROUTINE) || (gsym->type == GSYM_FUNCTION))
+       && gsym->ns->proc_name->backend_decl)
+    {
+      /* If the namespace has entries, the proc_name is the
+        entry master.  Find the entry and use its backend_decl.
+        otherwise, use the proc_name backend_decl.  */
+      if (gsym->ns->entries)
+       {
+         gfc_entry_list *entry = gsym->ns->entries;
+
+         for (; entry; entry = entry->next)
+           {
+             if (strcmp (gsym->name, entry->sym->name) == 0)
+               {
+                 sym->backend_decl = entry->sym->backend_decl;
+                 break;
+               }
+           }
+       }
+      else
+       {
+         sym->backend_decl = gsym->ns->proc_name->backend_decl;
+       }
+
+      if (sym->backend_decl)
+       return sym->backend_decl;
+    }
+
   if (sym->attr.intrinsic)
     {
       /* Call the resolution function to get the actual name.  This is
@@ -1424,7 +1528,7 @@ build_function_decl (gfc_symbol * sym)
   /* This specifies if a function is globally visible, i.e. it is
      the opposite of declaring static in C.  */
   if (DECL_CONTEXT (fndecl) == NULL_TREE
-      && !sym->attr.entry_master)
+      && !sym->attr.entry_master && !sym->attr.is_main_program)
     TREE_PUBLIC (fndecl) = 1;
 
   /* TREE_STATIC means the function body is defined here.  */
@@ -1443,12 +1547,6 @@ build_function_decl (gfc_symbol * sym)
       TREE_SIDE_EFFECTS (fndecl) = 0;
     }
 
-  /* For -fwhole-program to work well, the main program needs to have the
-     "externally_visible" attribute.  */
-  if (attr.is_main_program)
-    DECL_ATTRIBUTES (fndecl)
-      = tree_cons (get_identifier("externally_visible"), NULL_TREE, NULL_TREE);
-
   /* Layout the function declaration and put it in the binding level
      of the current function.  */
   pushdecl (fndecl);
@@ -1595,7 +1693,8 @@ create_function_arglist (gfc_symbol * sym)
          TREE_READONLY (length) = 1;
          gfc_finish_decl (length);
 
-         /* TODO: Check string lengths when -fbounds-check.  */
+         /* Remember the passed value.  */
+         f->sym->ts.cl->passed_length = length;
 
          /* Use the passed value for assumed length variables.  */
          if (!f->sym->ts.cl->length)
@@ -2473,6 +2572,19 @@ gfc_build_intrinsic_function_decls (void)
     gfc_build_library_function_decl (get_identifier (PREFIX ("iargc")),
                                     gfc_int4_type_node,
                                     0);
+
+  if (gfc_type_for_size (128, true))
+    {
+      tree uint128 = gfc_type_for_size (128, true);
+
+      gfor_fndecl_clz128 =
+       gfc_build_library_function_decl (get_identifier (PREFIX ("clz128")),
+                                        integer_type_node, 1, uint128);
+
+      gfor_fndecl_ctz128 =
+       gfc_build_library_function_decl (get_identifier (PREFIX ("ctz128")),
+                                        integer_type_node, 1, uint128);
+    }
 }
 
 
@@ -2533,6 +2645,11 @@ gfc_build_builtin_function_decls (void)
   /* The runtime_error function does not return.  */
   TREE_THIS_VOLATILE (gfor_fndecl_os_error) = 1;
 
+  gfor_fndecl_set_args =
+    gfc_build_library_function_decl (get_identifier (PREFIX("set_args")),
+                                    void_type_node, 2, integer_type_node,
+                                    build_pointer_type (pchar_type_node));
+
   gfor_fndecl_set_fpe =
     gfc_build_library_function_decl (get_identifier (PREFIX("set_fpe")),
                                    void_type_node, 1, integer_type_node);
@@ -2541,7 +2658,7 @@ gfc_build_builtin_function_decls (void)
   gfor_fndecl_set_options =
     gfc_build_library_function_decl (get_identifier (PREFIX("set_options")),
                                    void_type_node, 2, integer_type_node,
-                                   pvoid_type_node);
+                                   build_pointer_type (integer_type_node));
 
   gfor_fndecl_set_convert =
     gfc_build_library_function_decl (get_identifier (PREFIX("set_convert")),
@@ -2781,20 +2898,40 @@ gfc_init_default_dt (gfc_symbol * sym, tree body)
 }
 
 
-/* Initialize INTENT(OUT) derived type dummies.  */
+/* Initialize INTENT(OUT) derived type dummies.  As well as giving
+   them their default initializer, if they do not have allocatable
+   components, they have their allocatable components deallocated. */
+
 static tree
 init_intent_out_dt (gfc_symbol * proc_sym, tree body)
 {
   stmtblock_t fnblock;
   gfc_formal_arglist *f;
+  tree tmp;
+  tree present;
 
   gfc_init_block (&fnblock);
   for (f = proc_sym->formal; f; f = f->next)
     if (f->sym && f->sym->attr.intent == INTENT_OUT
-         && f->sym->ts.type == BT_DERIVED
-         && !f->sym->ts.derived->attr.alloc_comp
-         && f->sym->value)
-      body = gfc_init_default_dt (f->sym, body);
+         && f->sym->ts.type == BT_DERIVED)
+      {
+       if (f->sym->ts.derived->attr.alloc_comp)
+         {
+           tmp = gfc_deallocate_alloc_comp (f->sym->ts.derived,
+                                            f->sym->backend_decl,
+                                            f->sym->as ? f->sym->as->rank : 0);
+
+           present = gfc_conv_expr_present (f->sym);
+           tmp = build3 (COND_EXPR, TREE_TYPE (tmp), present,
+                         tmp, build_empty_stmt ());
+
+           gfc_add_expr_to_block (&fnblock, tmp);
+         }
+
+       if (!f->sym->ts.derived->attr.alloc_comp
+             && f->sym->value)
+         body = gfc_init_default_dt (f->sym, body);
+      }
 
   gfc_add_expr_to_block (&fnblock, body);
   return gfc_finish_block (&fnblock);
@@ -3101,11 +3238,12 @@ gfc_create_module_variable (gfc_symbol * sym)
       gfc_module_add_decl (cur_module, TYPE_STUB_DECL (decl));
     }
 
-  /* Only output variables and array valued, or derived type,
-     parameters.  */
+  /* Only output variables, procedure pointers and array valued,
+     or derived type, parameters.  */
   if (sym->attr.flavor != FL_VARIABLE
        && !(sym->attr.flavor == FL_PARAMETER
-              && (sym->attr.dimension || sym->ts.type == BT_DERIVED)))
+              && (sym->attr.dimension || sym->ts.type == BT_DERIVED))
+       && !(sym->attr.flavor == FL_PROCEDURE && sym->attr.proc_pointer))
     return;
 
   if ((sym->attr.in_common || sym->attr.in_equivalence) && sym->backend_decl)
@@ -3482,10 +3620,10 @@ generate_local_decl (gfc_symbol * sym)
   if (sym->attr.flavor == FL_VARIABLE)
     {
       if (!sym->attr.dummy && !sym->ns->proc_name->attr.entry_master)
-        generate_dependency_declarations (sym);
+       generate_dependency_declarations (sym);
 
       if (sym->attr.referenced)
-        gfc_get_symbol_decl (sym);
+       gfc_get_symbol_decl (sym);
       /* INTENT(out) dummy arguments are likely meant to be set.  */
       else if (warn_unused_variable
               && sym->attr.dummy
@@ -3502,20 +3640,34 @@ generate_local_decl (gfc_symbol * sym)
               && !(sym->attr.in_common || sym->attr.use_assoc || sym->mark))
        gfc_warning ("Unused variable '%s' declared at %L", sym->name,
                     &sym->declared_at);
+
       /* For variable length CHARACTER parameters, the PARM_DECL already
         references the length variable, so force gfc_get_symbol_decl
         even when not referenced.  If optimize > 0, it will be optimized
         away anyway.  But do this only after emitting -Wunused-parameter
         warning if requested.  */
-      if (sym->attr.dummy && ! sym->attr.referenced
-         && sym->ts.type == BT_CHARACTER
-         && sym->ts.cl->backend_decl != NULL
-         && TREE_CODE (sym->ts.cl->backend_decl) == VAR_DECL)
+      if (sym->attr.dummy && !sym->attr.referenced
+           && sym->ts.type == BT_CHARACTER
+           && sym->ts.cl->backend_decl != NULL
+           && TREE_CODE (sym->ts.cl->backend_decl) == VAR_DECL)
+       {
+         sym->attr.referenced = 1;
+         gfc_get_symbol_decl (sym);
+       }
+
+      /* INTENT(out) dummy arguments with allocatable components are reset
+        by default and need to be set referenced to generate the code for
+        automatic lengths.  */
+      if (sym->attr.dummy && !sym->attr.referenced
+           && sym->ts.type == BT_DERIVED
+           && sym->ts.derived->attr.alloc_comp
+           && sym->attr.intent == INTENT_OUT)
        {
          sym->attr.referenced = 1;
          gfc_get_symbol_decl (sym);
        }
 
+
       /* Check for dependencies in the array specification and string
        length, adding the necessary declarations to the function.  We
        mark the symbol now, as well as in traverse_ns, to prevent
@@ -3618,6 +3770,300 @@ gfc_trans_entry_master_switch (gfc_entry_list * el)
 }
 
 
+/* Add code to string lengths of actual arguments passed to a function against
+   the expected lengths of the dummy arguments.  */
+
+static void
+add_argument_checking (stmtblock_t *block, gfc_symbol *sym)
+{
+  gfc_formal_arglist *formal;
+
+  for (formal = sym->formal; formal; formal = formal->next)
+    if (formal->sym && formal->sym->ts.type == BT_CHARACTER)
+      {
+       enum tree_code comparison;
+       tree cond;
+       tree argname;
+       gfc_symbol *fsym;
+       gfc_charlen *cl;
+       const char *message;
+
+       fsym = formal->sym;
+       cl = fsym->ts.cl;
+
+       gcc_assert (cl);
+       gcc_assert (cl->passed_length != NULL_TREE);
+       gcc_assert (cl->backend_decl != NULL_TREE);
+
+       /* For POINTER, ALLOCATABLE and assumed-shape dummy arguments, the
+          string lengths must match exactly.  Otherwise, it is only required
+          that the actual string length is *at least* the expected one.  */
+       if (fsym->attr.pointer || fsym->attr.allocatable
+           || (fsym->as && fsym->as->type == AS_ASSUMED_SHAPE))
+         {
+           comparison = NE_EXPR;
+           message = _("Actual string length does not match the declared one"
+                       " for dummy argument '%s' (%ld/%ld)");
+         }
+       else
+         {
+           comparison = LT_EXPR;
+           message = _("Actual string length is shorter than the declared one"
+                       " for dummy argument '%s' (%ld/%ld)");
+         }
+
+       /* Build the condition.  For optional arguments, an actual length
+          of 0 is also acceptable if the associated string is NULL, which
+          means the argument was not passed.  */
+       cond = fold_build2 (comparison, boolean_type_node,
+                           cl->passed_length, cl->backend_decl);
+       if (fsym->attr.optional)
+         {
+           tree not_absent;
+           tree not_0length;
+           tree absent_failed;
+
+           not_0length = fold_build2 (NE_EXPR, boolean_type_node,
+                                      cl->passed_length,
+                                      fold_convert (gfc_charlen_type_node,
+                                                    integer_zero_node));
+           not_absent = fold_build2 (NE_EXPR, boolean_type_node,
+                                     fsym->backend_decl, null_pointer_node);
+
+           absent_failed = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+                                        not_0length, not_absent);
+
+           cond = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
+                               cond, absent_failed);
+         }
+
+       /* Build the runtime check.  */
+       argname = gfc_build_cstring_const (fsym->name);
+       argname = gfc_build_addr_expr (pchar_type_node, argname);
+       gfc_trans_runtime_check (true, false, cond, block, &fsym->declared_at,
+                                message, argname,
+                                fold_convert (long_integer_type_node,
+                                              cl->passed_length),
+                                fold_convert (long_integer_type_node,
+                                              cl->backend_decl));
+      }
+}
+
+
+static void
+create_main_function (tree fndecl)
+{
+  tree old_context;
+  tree ftn_main;
+  tree tmp, decl, result_decl, argc, argv, typelist, arglist;
+  stmtblock_t body;
+
+  old_context = current_function_decl;
+
+  if (old_context)
+    {
+      push_function_context ();
+      saved_parent_function_decls = saved_function_decls;
+      saved_function_decls = NULL_TREE;
+    }
+
+  /* main() function must be declared with global scope.  */
+  gcc_assert (current_function_decl == NULL_TREE);
+
+  /* Declare the function.  */
+  tmp =  build_function_type_list (integer_type_node, integer_type_node,
+                                  build_pointer_type (pchar_type_node),
+                                  NULL_TREE);
+  main_identifier_node = get_identifier ("main");
+  ftn_main = build_decl (FUNCTION_DECL, main_identifier_node, tmp);
+  ftn_main = build_decl (FUNCTION_DECL, get_identifier ("main"), tmp);
+  DECL_EXTERNAL (ftn_main) = 0;
+  TREE_PUBLIC (ftn_main) = 1;
+  TREE_STATIC (ftn_main) = 1;
+  DECL_ATTRIBUTES (ftn_main)
+      = tree_cons (get_identifier("externally_visible"), NULL_TREE, NULL_TREE);
+
+  /* Setup the result declaration (for "return 0").  */
+  result_decl = build_decl (RESULT_DECL, NULL_TREE, integer_type_node);
+  DECL_ARTIFICIAL (result_decl) = 1;
+  DECL_IGNORED_P (result_decl) = 1;
+  DECL_CONTEXT (result_decl) = ftn_main;
+  DECL_RESULT (ftn_main) = result_decl;
+
+  pushdecl (ftn_main);
+
+  /* Get the arguments.  */
+
+  arglist = NULL_TREE;
+  typelist = TYPE_ARG_TYPES (TREE_TYPE (ftn_main));
+
+  tmp = TREE_VALUE (typelist);
+  argc = build_decl (PARM_DECL, get_identifier ("argc"), tmp);
+  DECL_CONTEXT (argc) = ftn_main;
+  DECL_ARG_TYPE (argc) = TREE_VALUE (typelist);
+  TREE_READONLY (argc) = 1;
+  gfc_finish_decl (argc);
+  arglist = chainon (arglist, argc);
+
+  typelist = TREE_CHAIN (typelist);
+  tmp = TREE_VALUE (typelist);
+  argv = build_decl (PARM_DECL, get_identifier ("argv"), tmp);
+  DECL_CONTEXT (argv) = ftn_main;
+  DECL_ARG_TYPE (argv) = TREE_VALUE (typelist);
+  TREE_READONLY (argv) = 1;
+  DECL_BY_REFERENCE (argv) = 1;
+  gfc_finish_decl (argv);
+  arglist = chainon (arglist, argv);
+
+  DECL_ARGUMENTS (ftn_main) = arglist;
+  current_function_decl = ftn_main;
+  announce_function (ftn_main);
+
+  rest_of_decl_compilation (ftn_main, 1, 0);
+  make_decl_rtl (ftn_main);
+  init_function_start (ftn_main);
+  pushlevel (0);
+
+  gfc_init_block (&body);
+
+  /* Call some libgfortran initialization routines, call then MAIN__(). */
+
+  /* Call _gfortran_set_args (argc, argv).  */
+  TREE_USED (argc) = 1;
+  TREE_USED (argv) = 1;
+  tmp = build_call_expr (gfor_fndecl_set_args, 2, argc, argv);
+  gfc_add_expr_to_block (&body, tmp);
+
+  /* Add a call to set_options to set up the runtime library Fortran
+     language standard parameters.  */
+  {
+    tree array_type, array, var;
+
+    /* Passing a new option to the library requires four modifications:
+     + add it to the tree_cons list below
+          + change the array size in the call to build_array_type
+          + change the first argument to the library call
+            gfor_fndecl_set_options
+          + modify the library (runtime/compile_options.c)!  */
+
+    array = tree_cons (NULL_TREE, build_int_cst (integer_type_node,
+                      gfc_option.warn_std), NULL_TREE);
+    array = tree_cons (NULL_TREE, build_int_cst (integer_type_node,
+                      gfc_option.allow_std), array);
+    array = tree_cons (NULL_TREE, build_int_cst (integer_type_node, pedantic),
+                      array);
+    array = tree_cons (NULL_TREE, build_int_cst (integer_type_node,
+                      gfc_option.flag_dump_core), array);
+    array = tree_cons (NULL_TREE, build_int_cst (integer_type_node,
+                      gfc_option.flag_backtrace), array);
+    array = tree_cons (NULL_TREE, build_int_cst (integer_type_node,
+                      gfc_option.flag_sign_zero), array);
+
+    array = tree_cons (NULL_TREE, build_int_cst (integer_type_node,
+                      (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)), array);
+
+    array = tree_cons (NULL_TREE, build_int_cst (integer_type_node,
+                      gfc_option.flag_range_check), array);
+
+    array_type = build_array_type (integer_type_node,
+                      build_index_type (build_int_cst (NULL_TREE, 7)));
+    array = build_constructor_from_list (array_type, nreverse (array));
+    TREE_CONSTANT (array) = 1;
+    TREE_STATIC (array) = 1;
+
+    /* Create a static variable to hold the jump table.  */
+    var = gfc_create_var (array_type, "options");
+    TREE_CONSTANT (var) = 1;
+    TREE_STATIC (var) = 1;
+    TREE_READONLY (var) = 1;
+    DECL_INITIAL (var) = array;
+    var = gfc_build_addr_expr (build_pointer_type (integer_type_node), var);
+
+    tmp = build_call_expr (gfor_fndecl_set_options, 2,
+                          build_int_cst (integer_type_node, 8), var);
+    gfc_add_expr_to_block (&body, tmp);
+  }
+
+  /* If -ffpe-trap option was provided, add a call to set_fpe so that
+     the library will raise a FPE when needed.  */
+  if (gfc_option.fpe != 0)
+    {
+      tmp = build_call_expr (gfor_fndecl_set_fpe, 1,
+                            build_int_cst (integer_type_node,
+                                           gfc_option.fpe));
+      gfc_add_expr_to_block (&body, tmp);
+    }
+
+  /* If this is the main program and an -fconvert option was provided,
+     add a call to set_convert.  */
+
+  if (gfc_option.convert != GFC_CONVERT_NATIVE)
+    {
+      tmp = build_call_expr (gfor_fndecl_set_convert, 1,
+                            build_int_cst (integer_type_node,
+                                           gfc_option.convert));
+      gfc_add_expr_to_block (&body, tmp);
+    }
+
+  /* If this is the main program and an -frecord-marker option was provided,
+     add a call to set_record_marker.  */
+
+  if (gfc_option.record_marker != 0)
+    {
+      tmp = build_call_expr (gfor_fndecl_set_record_marker, 1,
+                            build_int_cst (integer_type_node,
+                                           gfc_option.record_marker));
+      gfc_add_expr_to_block (&body, tmp);
+    }
+
+  if (gfc_option.max_subrecord_length != 0)
+    {
+      tmp = build_call_expr (gfor_fndecl_set_max_subrecord_length, 1,
+                            build_int_cst (integer_type_node,
+                                           gfc_option.max_subrecord_length));
+      gfc_add_expr_to_block (&body, tmp);
+    }
+
+  /* Call MAIN__().  */
+  tmp = build_call_expr (fndecl, 0);
+  gfc_add_expr_to_block (&body, tmp);
+
+  /* Mark MAIN__ as used.  */
+  TREE_USED (fndecl) = 1;
+
+  /* "return 0".  */
+  tmp = fold_build2 (MODIFY_EXPR, integer_type_node, DECL_RESULT (ftn_main),
+                    build_int_cst (integer_type_node, 0));
+  tmp = build1_v (RETURN_EXPR, tmp);
+  gfc_add_expr_to_block (&body, tmp);
+
+
+  DECL_SAVED_TREE (ftn_main) = gfc_finish_block (&body);
+  decl = getdecls ();
+
+  /* Finish off this function and send it for code generation.  */
+  poplevel (1, 0, 1);
+  BLOCK_SUPERCONTEXT (DECL_INITIAL (ftn_main)) = ftn_main;
+
+  DECL_SAVED_TREE (ftn_main)
+    = build3_v (BIND_EXPR, decl, DECL_SAVED_TREE (ftn_main),
+               DECL_INITIAL (ftn_main));
+
+  /* Output the GENERIC tree.  */
+  dump_function (TDI_original, ftn_main);
+
+  gfc_gimplify_function (ftn_main);
+  cgraph_finalize_function (ftn_main, false);
+
+  if (old_context)
+    {
+      pop_function_context ();
+      saved_function_decls = saved_parent_function_decls;
+    }
+  current_function_decl = old_context;
+}
+
+
 /* Generate code for a function.  */
 
 void
@@ -3631,8 +4077,10 @@ gfc_generate_function_code (gfc_namespace * ns)
   stmtblock_t block;
   stmtblock_t body;
   tree result;
+  tree recurcheckvar = NULL;
   gfc_symbol *sym;
   int rank;
+  bool is_recursive;
 
   sym = ns->proc_name;
 
@@ -3682,6 +4130,9 @@ gfc_generate_function_code (gfc_namespace * ns)
 
   gfc_generate_contained_functions (ns);
 
+  nonlocal_dummy_decls = NULL;
+  nonlocal_dummy_decl_pset = NULL;
+
   generate_local_vars (ns);
 
   /* Keep the parent fake result declaration in module functions
@@ -3697,104 +4148,23 @@ gfc_generate_function_code (gfc_namespace * ns)
   /* Now generate the code for the body of this function.  */
   gfc_init_block (&body);
 
-  /* If this is the main program, add a call to set_options to set up the
-     runtime library Fortran language standard parameters.  */
-  if (sym->attr.is_main_program)
-    {
-      tree array_type, array, var;
-
-      /* Passing a new option to the library requires four modifications:
-          + add it to the tree_cons list below
-          + change the array size in the call to build_array_type
-          + change the first argument to the library call
-            gfor_fndecl_set_options
-          + modify the library (runtime/compile_options.c)!  */
-      array = tree_cons (NULL_TREE,
-                        build_int_cst (integer_type_node,
-                                       gfc_option.warn_std), NULL_TREE);
-      array = tree_cons (NULL_TREE,
-                        build_int_cst (integer_type_node,
-                                       gfc_option.allow_std), array);
-      array = tree_cons (NULL_TREE,
-                        build_int_cst (integer_type_node, pedantic), array);
-      array = tree_cons (NULL_TREE,
-                        build_int_cst (integer_type_node,
-                                       gfc_option.flag_dump_core), array);
-      array = tree_cons (NULL_TREE,
-                        build_int_cst (integer_type_node,
-                                       gfc_option.flag_backtrace), array);
-      array = tree_cons (NULL_TREE,
-                        build_int_cst (integer_type_node,
-                                       gfc_option.flag_sign_zero), array);
-
-      array = tree_cons (NULL_TREE,
-                        build_int_cst (integer_type_node,
-                                       flag_bounds_check), array);
-
-      array = tree_cons (NULL_TREE,
-                        build_int_cst (integer_type_node,
-                                       gfc_option.flag_range_check), array);
-
-      array_type = build_array_type (integer_type_node,
-                                    build_index_type (build_int_cst (NULL_TREE,
-                                                                     7)));
-      array = build_constructor_from_list (array_type, nreverse (array));
-      TREE_CONSTANT (array) = 1;
-      TREE_STATIC (array) = 1;
-
-      /* Create a static variable to hold the jump table.  */
-      var = gfc_create_var (array_type, "options");
-      TREE_CONSTANT (var) = 1;
-      TREE_STATIC (var) = 1;
-      TREE_READONLY (var) = 1;
-      DECL_INITIAL (var) = array;
-      var = gfc_build_addr_expr (pvoid_type_node, var);
-
-      tmp = build_call_expr (gfor_fndecl_set_options, 2,
-                            build_int_cst (integer_type_node, 8), var);
-      gfc_add_expr_to_block (&body, tmp);
-    }
-
-  /* If this is the main program and a -ffpe-trap option was provided,
-     add a call to set_fpe so that the library will raise a FPE when
-     needed.  */
-  if (sym->attr.is_main_program && gfc_option.fpe != 0)
-    {
-      tmp = build_call_expr (gfor_fndecl_set_fpe, 1,
-                            build_int_cst (integer_type_node,
-                                           gfc_option.fpe));
-      gfc_add_expr_to_block (&body, tmp);
-    }
-
-  /* If this is the main program and an -fconvert option was provided,
-     add a call to set_convert.  */
-
-  if (sym->attr.is_main_program && gfc_option.convert != GFC_CONVERT_NATIVE)
-    {
-      tmp = build_call_expr (gfor_fndecl_set_convert, 1,
-                            build_int_cst (integer_type_node,
-                                           gfc_option.convert));
-      gfc_add_expr_to_block (&body, tmp);
-    }
-
-  /* If this is the main program and an -frecord-marker option was provided,
-     add a call to set_record_marker.  */
-
-  if (sym->attr.is_main_program && gfc_option.record_marker != 0)
-    {
-      tmp = build_call_expr (gfor_fndecl_set_record_marker, 1,
-                            build_int_cst (integer_type_node,
-                                           gfc_option.record_marker));
-      gfc_add_expr_to_block (&body, tmp);
-    }
-
-  if (sym->attr.is_main_program && gfc_option.max_subrecord_length != 0)
-    {
-      tmp = build_call_expr (gfor_fndecl_set_max_subrecord_length,
-                            1,
-                            build_int_cst (integer_type_node,
-                                           gfc_option.max_subrecord_length));
-      gfc_add_expr_to_block (&body, tmp);
+   is_recursive = sym->attr.recursive
+                 || (sym->attr.entry_master
+                     && sym->ns->entries->sym->attr.recursive);
+   if ((gfc_option.rtcheck & GFC_RTCHECK_RECURSION) && !is_recursive)
+     {
+       char * msg;
+
+       asprintf (&msg, "Recursive call to nonrecursive procedure '%s'",
+                sym->name);
+       recurcheckvar = gfc_create_var (boolean_type_node, "is_recursive");
+       TREE_STATIC (recurcheckvar) = 1;
+       DECL_INITIAL (recurcheckvar) = boolean_false_node;
+       gfc_add_expr_to_block (&block, recurcheckvar);
+       gfc_trans_runtime_check (true, false, recurcheckvar, &block,
+                               &sym->declared_at, msg);
+       gfc_add_modify (&block, recurcheckvar, boolean_true_node);
+       gfc_free (msg);
     }
 
   if (TREE_TYPE (DECL_RESULT (fndecl)) != void_type_node
@@ -3812,6 +4182,12 @@ gfc_generate_function_code (gfc_namespace * ns)
       gfc_add_expr_to_block (&body, tmp);
     }
 
+  /* If bounds-checking is enabled, generate code to check passed in actual
+     arguments against the expected dummy argument attributes (e.g. string
+     lengths).  */
+  if (flag_bounds_check)
+    add_argument_checking (&body, sym);
+
   tmp = gfc_trans_code (ns->code);
   gfc_add_expr_to_block (&body, tmp);
 
@@ -3851,6 +4227,13 @@ gfc_generate_function_code (gfc_namespace * ns)
 
       gfc_add_expr_to_block (&block, tmp);
 
+      /* Reset recursion-check variable.  */
+      if ((gfc_option.rtcheck & GFC_RTCHECK_RECURSION) && !is_recursive)
+      {
+       gfc_add_modify (&block, recurcheckvar, boolean_false_node);
+       recurcheckvar = NULL;
+      }
+
       if (result == NULL_TREE)
        {
          /* TODO: move to the appropriate place in resolve.c.  */
@@ -3873,7 +4256,15 @@ gfc_generate_function_code (gfc_namespace * ns)
        }
     }
   else
-    gfc_add_expr_to_block (&block, tmp);
+    {
+      gfc_add_expr_to_block (&block, tmp);
+      /* Reset recursion-check variable.  */
+      if ((gfc_option.rtcheck & GFC_RTCHECK_RECURSION) && !is_recursive)
+      {
+       gfc_add_modify (&block, recurcheckvar, boolean_false_node);
+       recurcheckvar = NULL;
+      }
+    }
 
 
   /* Add all the decls we created during processing.  */
@@ -3900,6 +4291,15 @@ gfc_generate_function_code (gfc_namespace * ns)
     = build3_v (BIND_EXPR, decl, DECL_SAVED_TREE (fndecl),
                DECL_INITIAL (fndecl));
 
+  if (nonlocal_dummy_decls)
+    {
+      BLOCK_VARS (DECL_INITIAL (fndecl))
+       = chainon (BLOCK_VARS (DECL_INITIAL (fndecl)), nonlocal_dummy_decls);
+      pointer_set_destroy (nonlocal_dummy_decl_pset);
+      nonlocal_dummy_decls = NULL;
+      nonlocal_dummy_decl_pset = NULL;
+    }
+
   /* Output the GENERIC tree.  */
   dump_function (TDI_original, fndecl);
 
@@ -3931,8 +4331,12 @@ gfc_generate_function_code (gfc_namespace * ns)
 
   gfc_trans_use_stmts (ns);
   gfc_traverse_ns (ns, gfc_emit_parameter_debug_info);
+
+  if (sym->attr.is_main_program)
+    create_main_function (fndecl);
 }
 
+
 void
 gfc_generate_constructors (void)
 {