OSDN Git Service

fortran/
[pf3gnuchains/gcc-fork.git] / gcc / fortran / trans-expr.c
index 2322705..d1570a7 100644 (file)
@@ -296,6 +296,11 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr)
 {
   gfc_ref *ref;
   gfc_symbol *sym;
+  tree parent_decl;
+  int parent_flag;
+  bool return_value;
+  bool alternate_entry;
+  bool entry_master;
 
   sym = expr->symtree->n.sym;
   if (se->ss != NULL)
@@ -317,32 +322,51 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr)
 
       se->expr = gfc_get_symbol_decl (sym);
 
+      /* Deal with references to a parent results or entries by storing
+        the current_function_decl and moving to the parent_decl.  */
+      parent_flag = 0;
+
+      return_value = sym->attr.function && sym->result == sym;
+      alternate_entry = sym->attr.function && sym->attr.entry
+                         && sym->result == sym;
+      entry_master = sym->attr.result
+                       && sym->ns->proc_name->attr.entry_master
+                       && !gfc_return_by_reference (sym->ns->proc_name);
+      parent_decl = DECL_CONTEXT (current_function_decl);
+
+      if ((se->expr == parent_decl && return_value)
+           || (sym->ns  && sym->ns->proc_name
+                 && sym->ns->proc_name->backend_decl == parent_decl
+                 && (alternate_entry || entry_master)))
+       parent_flag = 1;
+      else
+       parent_flag = 0;
+
       /* Special case for assigning the return value of a function.
         Self recursive functions must have an explicit return value.  */
-      if (se->expr == current_function_decl && sym->attr.function
-         && (sym->result == sym))
-       se_expr = gfc_get_fake_result_decl (sym);
+      if (sym->attr.function && sym->result == sym
+           && (se->expr == current_function_decl || parent_flag))
+       se_expr = gfc_get_fake_result_decl (sym, parent_flag);
 
       /* Similarly for alternate entry points.  */
-      else if (sym->attr.function && sym->attr.entry
-              && (sym->result == sym)
-              && sym->ns->proc_name->backend_decl == current_function_decl)
+      else if (alternate_entry 
+                && (sym->ns->proc_name->backend_decl == current_function_decl
+                       || parent_flag))
        {
          gfc_entry_list *el = NULL;
 
          for (el = sym->ns->entries; el; el = el->next)
            if (sym == el->sym)
              {
-               se_expr = gfc_get_fake_result_decl (sym);
+               se_expr = gfc_get_fake_result_decl (sym, parent_flag);
                break;
              }
        }
 
-      else if (sym->attr.result
-              && sym->ns->proc_name->backend_decl == current_function_decl
-              && sym->ns->proc_name->attr.entry_master
-              && !gfc_return_by_reference (sym->ns->proc_name))
-       se_expr = gfc_get_fake_result_decl (sym);
+      else if (entry_master
+                && (sym->ns->proc_name->backend_decl == current_function_decl
+                       || parent_flag))
+       se_expr = gfc_get_fake_result_decl (sym, parent_flag);
 
       if (se_expr)
        se->expr = se_expr;
@@ -925,6 +949,7 @@ gfc_conv_expr_op (gfc_se * se, gfc_expr * expr)
   switch (expr->value.op.operator)
     {
     case INTRINSIC_UPLUS:
+    case INTRINSIC_PARENTHESES:
       gfc_conv_expr (se, expr->value.op.op1);
       return;
 
@@ -1291,6 +1316,7 @@ gfc_add_interface_mapping (gfc_interface_mapping * mapping,
   new_sym->attr.referenced = 1;
   new_sym->attr.dimension = sym->attr.dimension;
   new_sym->attr.pointer = sym->attr.pointer;
+  new_sym->attr.allocatable = sym->attr.allocatable;
   new_sym->attr.flavor = sym->attr.flavor;
 
   /* Create a fake symtree for it.  */
@@ -1342,8 +1368,13 @@ gfc_add_interface_mapping (gfc_interface_mapping * mapping,
        value = build_fold_indirect_ref (value);
     }
 
-  /* If the argument is a scalar or a pointer to an array, dereference it.  */
-  else if (!sym->attr.dimension || sym->attr.pointer)
+  /* If the argument is a scalar, a pointer to an array or an allocatable,
+     dereference it.  */
+  else if (!sym->attr.dimension || sym->attr.pointer || sym->attr.allocatable)
+    value = build_fold_indirect_ref (se->expr);
+  
+  /* For character(*), use the actual argument's descriptor.  */  
+  else if (sym->ts.type == BT_CHARACTER && !new_sym->ts.cl->length)
     value = build_fold_indirect_ref (se->expr);
 
   /* If the argument is an array descriptor, use it to determine
@@ -1865,16 +1896,15 @@ gfc_conv_function_call (gfc_se * se, gfc_symbol * sym,
             }
          else
            {
-             /* If the procedure requires an explicit interface, the
-                actual argument is passed according to the
-                corresponding formal argument.  If the corresponding
-                formal argument is a POINTER or assumed shape, we do
-                not use g77's calling convention, and pass the
-                address of the array descriptor instead. Otherwise we
-                use g77's calling convention.  */
+              /* If the procedure requires an explicit interface, the actual
+                 argument is passed according to the corresponding formal
+                 argument.  If the corresponding formal argument is a POINTER,
+                 ALLOCATABLE or assumed shape, we do not use g77's calling
+                 convention, and pass the address of the array descriptor
+                 instead. Otherwise we use g77's calling convention.  */
              int f;
              f = (formal != NULL)
-                 && !formal->sym->attr.pointer
+                 && !(formal->sym->attr.pointer || formal->sym->attr.allocatable)
                  && formal->sym->as->type != AS_ASSUMED_SHAPE;
              f = f || !sym->attr.always_explicit;
              if (arg->expr->expr_type == EXPR_VARIABLE
@@ -1886,6 +1916,16 @@ gfc_conv_function_call (gfc_se * se, gfc_symbol * sym,
                gfc_conv_aliased_arg (&parmse, arg->expr, f);
              else
                gfc_conv_array_parameter (&parmse, arg->expr, argss, f);
+
+              /* If an ALLOCATABLE dummy argument has INTENT(OUT) and is 
+                 allocated on entry, it must be deallocated.  */
+              if (formal && formal->sym->attr.allocatable
+                  && formal->sym->attr.intent == INTENT_OUT)
+                {
+                  tmp = gfc_trans_dealloc_allocated (arg->expr->symtree->n.sym);
+                  gfc_add_expr_to_block (&se->pre, tmp);
+                }
+
            } 
        }
 
@@ -1952,9 +1992,11 @@ gfc_conv_function_call (gfc_se * se, gfc_symbol * sym,
          /* Evaluate the bounds of the result, if known.  */
          gfc_set_loop_bounds_from_array_spec (&mapping, se, sym->result->as);
 
-         /* Allocate a temporary to store the result.  */
-         gfc_trans_allocate_temp_array (&se->pre, &se->post,
-                                        se->loop, info, tmp, false);
+         /* Allocate a temporary to store the result.  In case the function
+             returns a pointer, the temporary will be a shallow copy and
+             mustn't be deallocated.  */
+          gfc_trans_allocate_temp_array (&se->pre, &se->post, se->loop, info,
+                                         tmp, false, !sym->attr.pointer);
 
          /* Zero the first stride to indicate a temporary.  */
          tmp = gfc_conv_descriptor_stride (info->descriptor, gfc_rank_cst[0]);
@@ -2656,7 +2698,7 @@ gfc_conv_expr_lhs (gfc_se * se, gfc_expr * expr)
 }
 
 /* Like gfc_conv_expr, but the POST block is guaranteed to be empty for
-   numeric expressions.  Used for scalar values whee inserting cleanup code
+   numeric expressions.  Used for scalar values where inserting cleanup code
    is inconvenient.  */
 void
 gfc_conv_expr_val (gfc_se * se, gfc_expr * expr)
@@ -2912,6 +2954,10 @@ gfc_trans_arrayfunc_assign (gfc_expr * expr1, gfc_expr * expr2)
   if (gfc_ref_needs_temporary_p (expr1->ref))
     return NULL;
 
+  /* Functions returning pointers need temporaries.  */
+  if (expr2->symtree->n.sym->attr.pointer)
+    return NULL;
+
   /* Check that no LHS component references appear during an array
      reference. This is needed because we do not have the means to
      span any arbitrary stride with an array descriptor. This check