OSDN Git Service

PR libfortran/20006
[pf3gnuchains/gcc-fork.git] / gcc / fortran / trans.c
index aed764d..a3c3ddc 100644 (file)
@@ -1,36 +1,33 @@
 /* Code translation -- generate GCC trees from gfc_code.
-   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Contributed by Paul Brook
 
-This file is part of GNU G95.
+This file is part of GCC.
 
-GNU G95 is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU G95 is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU G95; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
 #include "tree.h"
-#include "tree-simple.h"
-#include <stdio.h>
+#include "tree-gimple.h"
 #include "ggc.h"
 #include "toplev.h"
 #include "defaults.h"
 #include "real.h"
-#include <gmp.h>
-#include <assert.h>
 #include "gfortran.h"
 #include "trans.h"
 #include "trans-stmt.h"
@@ -56,7 +53,7 @@ gfc_advance_chain (tree t, int n)
 {
   for (; n > 0; n--)
     {
-      assert (t != NULL_TREE);
+      gcc_assert (t != NULL_TREE);
       t = TREE_CHAIN (t);
     }
   return t;
@@ -128,7 +125,7 @@ gfc_evaluate_now (tree expr, stmtblock_t * pblock)
 {
   tree var;
 
-  if (TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
+  if (CONSTANT_CLASS_P (expr))
     return expr;
 
   var = gfc_create_var (TREE_TYPE (expr), NULL);
@@ -146,13 +143,22 @@ gfc_add_modify_expr (stmtblock_t * pblock, tree lhs, tree rhs)
 {
   tree tmp;
 
-  tmp = fold (build_v (MODIFY_EXPR, lhs, rhs));
+#ifdef ENABLE_CHECKING
+  /* Make sure that the types of the rhs and the lhs are the same
+     for scalar assignments.  We should probably have something
+     similar for aggregates, but right now removing that check just
+     breaks everything.  */
+  gcc_assert (TREE_TYPE (rhs) == TREE_TYPE (lhs)
+             || AGGREGATE_TYPE_P (TREE_TYPE (lhs)));
+#endif
+
+  tmp = fold_build2 (MODIFY_EXPR, void_type_node, lhs, rhs);
   gfc_add_expr_to_block (pblock, tmp);
 }
 
 
 /* Create a new scope/binding level and initialize a block.  Care must be
-   taken when translating expessions as any temporaries will be placed in
+   taken when translating expressions as any temporaries will be placed in
    the innermost scope.  */
 
 void
@@ -187,7 +193,7 @@ gfc_merge_block_scope (stmtblock_t * block)
   tree decl;
   tree next;
 
-  assert (block->has_scope);
+  gcc_assert (block->has_scope);
   block->has_scope = 0;
 
   /* Remember the decls in this scope.  */
@@ -215,7 +221,10 @@ gfc_finish_block (stmtblock_t * stmtblock)
   tree expr;
   tree block;
 
-  expr = rationalize_compound_expr (stmtblock->head);
+  expr = stmtblock->head;
+  if (!expr)
+    expr = build_empty_stmt ();
+
   stmtblock->head = NULL_TREE;
 
   if (stmtblock->has_scope)
@@ -225,7 +234,7 @@ gfc_finish_block (stmtblock_t * stmtblock)
       if (decl)
        {
          block = poplevel (1, 0, 0);
-         expr = build_v (BIND_EXPR, decl, expr, block);
+         expr = build3_v (BIND_EXPR, decl, expr, block);
        }
       else
        poplevel (0, 0, 0);
@@ -279,8 +288,7 @@ tree
 gfc_build_indirect_ref (tree t)
 {
   tree type = TREE_TYPE (t);
-  if (!POINTER_TYPE_P (type))
-    abort ();
+  gcc_assert (POINTER_TYPE_P (type));
   type = TREE_TYPE (type);
 
   if (TREE_CODE (t) == ADDR_EXPR)
@@ -296,18 +304,17 @@ tree
 gfc_build_array_ref (tree base, tree offset)
 {
   tree type = TREE_TYPE (base);
-  if (TREE_CODE (type) != ARRAY_TYPE)
-    abort ();
+  gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
   type = TREE_TYPE (type);
 
   if (DECL_P (base))
     TREE_ADDRESSABLE (base) = 1;
 
-  return build (ARRAY_REF, type, base, offset);
+  return build4 (ARRAY_REF, type, base, offset, NULL_TREE, NULL_TREE);
 }
 
 
-/* Given a funcion declaration FNDECL and an argument list ARGLIST,
+/* Given a function declaration FNDECL and an argument list ARGLIST,
    build a CALL_EXPR.  */
 
 tree
@@ -317,7 +324,8 @@ gfc_build_function_call (tree fndecl, tree arglist)
   tree call;
 
   fn = gfc_build_addr_expr (NULL, fndecl);
-  call = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fndecl)), fn, arglist, NULL);
+  call = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fndecl)), 
+                fn, arglist, NULL);
   TREE_SIDE_EFFECTS (call) = 1;
 
   return call;
@@ -342,7 +350,7 @@ gfc_trans_runtime_check (tree cond, tree msg, stmtblock_t * pblock)
   /* The code to generate the error.  */
   gfc_start_block (&block);
 
-  assert (TREE_CODE (msg) == STRING_CST);
+  gcc_assert (TREE_CODE (msg) == STRING_CST);
 
   TREE_USED (msg) = 1;
 
@@ -352,7 +360,7 @@ gfc_trans_runtime_check (tree cond, tree msg, stmtblock_t * pblock)
   tmp = gfc_build_addr_expr (pchar_type_node, gfc_strconst_current_filename);
   args = gfc_chainon_list (args, tmp);
 
-  tmp = build_int_2 (input_line, 0);
+  tmp = build_int_cst (NULL_TREE, input_line);
   args = gfc_chainon_list (args, tmp);
 
   tmp = gfc_build_function_call (gfor_fndecl_runtime_error, args);
@@ -366,31 +374,44 @@ gfc_trans_runtime_check (tree cond, tree msg, stmtblock_t * pblock)
     }
   else
     {
-      /* Tell the compiler that this isn't likley.  */
+      /* Tell the compiler that this isn't likely.  */
       tmp = gfc_chainon_list (NULL_TREE, cond);
       tmp = gfc_chainon_list (tmp, integer_zero_node);
       cond = gfc_build_function_call (built_in_decls[BUILT_IN_EXPECT], tmp);
 
-      tmp = build_v (COND_EXPR, cond, body, build_empty_stmt ());
+      tmp = build3_v (COND_EXPR, cond, body, build_empty_stmt ());
       gfc_add_expr_to_block (pblock, tmp);
     }
 }
 
 
-/* Add a statement to a bock.  */
+/* Add a statement to a block.  */
 
 void
 gfc_add_expr_to_block (stmtblock_t * block, tree expr)
 {
-  assert (block);
+  gcc_assert (block);
 
   if (expr == NULL_TREE || IS_EMPTY_STMT (expr))
     return;
 
-  expr = fold (expr);
+  if (TREE_CODE (expr) != STATEMENT_LIST)
+    expr = fold (expr);
+
   if (block->head)
-    block->head = build_v (COMPOUND_EXPR, block->head, expr);
+    {
+      if (TREE_CODE (block->head) != STATEMENT_LIST)
+       {
+         tree tmp;
+
+         tmp = block->head;
+         block->head = NULL_TREE;
+         append_to_statement_list (tmp, &block->head);
+       }
+      append_to_statement_list (expr, &block->head);
+    }
   else
+    /* Don't bother creating a list if we only have a single statement.  */
     block->head = expr;
 }
 
@@ -400,8 +421,8 @@ gfc_add_expr_to_block (stmtblock_t * block, tree expr)
 void
 gfc_add_block_to_block (stmtblock_t * block, stmtblock_t * append)
 {
-  assert (append);
-  assert (!append->has_scope);
+  gcc_assert (append);
+  gcc_assert (!append->has_scope);
 
   gfc_add_expr_to_block (block, append->head);
   append->head = NULL_TREE;
@@ -409,13 +430,18 @@ gfc_add_block_to_block (stmtblock_t * block, stmtblock_t * append)
 
 
 /* Get the current locus.  The structure may not be complete, and should
-   only be used with gfc_set_current_locus.  */
+   only be used with gfc_set_backend_locus.  */
 
 void
 gfc_get_backend_locus (locus * loc)
 {
-  loc->line = input_line - 1;
-  loc->file = gfc_current_backend_file;
+  loc->lb = gfc_getmem (sizeof (gfc_linebuf));    
+#ifdef USE_MAPPED_LOCATION
+  loc->lb->location = input_location;
+#else
+  loc->lb->linenum = input_line;
+#endif
+  loc->lb->file = gfc_current_backend_file;
 }
 
 
@@ -424,9 +450,13 @@ gfc_get_backend_locus (locus * loc)
 void
 gfc_set_backend_locus (locus * loc)
 {
-  input_line = loc->line + 1;
-  gfc_current_backend_file = loc->file;
-  input_filename = loc->file->filename;
+  gfc_current_backend_file = loc->lb->file;
+#ifdef USE_MAPPED_LOCATION
+  input_location = loc->lb->location;
+#else
+  input_line = loc->lb->linenum;
+  input_filename = loc->lb->file->filename;
+#endif
 }
 
 
@@ -443,12 +473,10 @@ gfc_trans_code (gfc_code * code)
 
   gfc_start_block (&block);
 
-  /* Translate statements one by one to SIMPLE trees until we reach
+  /* Translate statements one by one to GIMPLE trees until we reach
      the end of this gfc_code branch.  */
   for (; code; code = code->next)
     {
-      gfc_set_backend_locus (&code->loc);
-
       if (code->here != 0)
        {
          res = gfc_trans_label_here (code);
@@ -489,6 +517,10 @@ gfc_trans_code (gfc_code * code)
          res = gfc_trans_goto (code);
          break;
 
+       case EXEC_ENTRY:
+         res = gfc_trans_entry (code);
+         break;
+
        case EXEC_PAUSE:
          res = gfc_trans_pause (code);
          break;
@@ -525,6 +557,10 @@ gfc_trans_code (gfc_code * code)
          res = gfc_trans_select (code);
          break;
 
+       case EXEC_FLUSH:
+         res = gfc_trans_flush (code);
+         break;
+
        case EXEC_FORALL:
          res = gfc_trans_forall (code);
          break;
@@ -589,10 +625,16 @@ gfc_trans_code (gfc_code * code)
          internal_error ("gfc_trans_code(): Bad statement code");
        }
 
+      gfc_set_backend_locus (&code->loc);
+
       if (res != NULL_TREE && ! IS_EMPTY_STMT (res))
        {
-         annotate_with_locus (res, input_location);
-         /* Add the new statemment to the block.  */
+         if (TREE_CODE (res) == STATEMENT_LIST)
+           annotate_all_with_locus (&res, input_location);
+         else
+           SET_EXPR_LOCATION (res, input_location);
+           
+         /* Add the new statement to the block.  */
          gfc_add_expr_to_block (&block, res);
        }
     }
@@ -608,12 +650,18 @@ gfc_trans_code (gfc_code * code)
 void
 gfc_generate_code (gfc_namespace * ns)
 {
-  gfc_symbol *main_program = NULL;
-  symbol_attribute attr;
+  if (ns->is_block_data)
+    {
+      gfc_generate_block_data (ns);
+      return;
+    }
 
   /* Main program subroutine.  */
   if (!ns->proc_name)
     {
+      gfc_symbol *main_program;
+      symbol_attribute attr;
+
       /* Lots of things get upset if a subroutine doesn't have a symbol, so we
          make one now.  Hopefully we've set all the required fields.  */
       gfc_get_symbol ("MAIN__", ns, &main_program);
@@ -622,7 +670,12 @@ gfc_generate_code (gfc_namespace * ns)
       attr.proc = PROC_UNKNOWN;
       attr.subroutine = 1;
       attr.access = ACCESS_PUBLIC;
+      attr.is_main_program = 1;
       main_program->attr = attr;
+
+      /* Set the location to the first line of code.  */
+      if (ns->code)
+       main_program->declared_at = ns->code->loc;
       ns->proc_name = main_program;
       gfc_commit_symbols ();
     }
@@ -648,7 +701,7 @@ gfc_generate_module_code (gfc_namespace * ns)
       if (!n->proc_name)
         continue;
 
-      gfc_build_function_decl (n->proc_name);
+      gfc_create_function_decl (n);
     }
 
   for (n = ns->contained; n; n = n->sibling)