OSDN Git Service

2010-09-24 Steven G. Kargl < kargl@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / fortran / interface.c
index 1e72a90..896ad75 100644 (file)
@@ -314,12 +314,42 @@ gfc_match_end_interface (void)
        {
 
          if (current_interface.op == INTRINSIC_ASSIGN)
-           gfc_error ("Expected 'END INTERFACE ASSIGNMENT (=)' at %C");
+           {
+             m = MATCH_ERROR;
+             gfc_error ("Expected 'END INTERFACE ASSIGNMENT (=)' at %C");
+           }
          else
-           gfc_error ("Expecting 'END INTERFACE OPERATOR (%s)' at %C",
-                      gfc_op2string (current_interface.op));
+           {
+             char *s1, *s2;
+             s1 = gfc_op2string (current_interface.op);
+             s2 = gfc_op2string (op);
+
+             /* The following if-statements are used to enforce C1202
+                from F2003.  */
+             if ((strcmp(s1, "==") == 0 && strcmp(s2, ".eq.") == 0)
+                 || (strcmp(s1, ".eq.") == 0 && strcmp(s2, "==") == 0))
+               break;
+             if ((strcmp(s1, "/=") == 0 && strcmp(s2, ".ne.") == 0)
+                 || (strcmp(s1, ".ne.") == 0 && strcmp(s2, "/=") == 0))
+               break;
+             if ((strcmp(s1, "<=") == 0 && strcmp(s2, ".le.") == 0)
+                 || (strcmp(s1, ".le.") == 0 && strcmp(s2, "<=") == 0))
+               break;
+             if ((strcmp(s1, "<") == 0 && strcmp(s2, ".lt.") == 0)
+                 || (strcmp(s1, ".lt.") == 0 && strcmp(s2, "<") == 0))
+               break;
+             if ((strcmp(s1, ">=") == 0 && strcmp(s2, ".ge.") == 0)
+                 || (strcmp(s1, ".ge.") == 0 && strcmp(s2, ">=") == 0))
+               break;
+             if ((strcmp(s1, ">") == 0 && strcmp(s2, ".gt.") == 0)
+                 || (strcmp(s1, ".gt.") == 0 && strcmp(s2, ">") == 0))
+               break;
 
-         m = MATCH_ERROR;
+             m = MATCH_ERROR;
+             gfc_error ("Expecting 'END INTERFACE OPERATOR (%s)' at %C, "
+                        "but got %s", s1, s2);
+           }
+               
        }
 
       break;
@@ -1368,6 +1398,11 @@ compare_pointer (gfc_symbol *formal, gfc_expr *actual)
   if (formal->attr.pointer)
     {
       attr = gfc_expr_attr (actual);
+
+      /* Fortran 2008 allows non-pointer actual arguments.  */
+      if (!attr.pointer && attr.target && formal->attr.intent == INTENT_IN)
+       return 2;
+
       if (!attr.pointer)
        return 0;
     }
@@ -1423,10 +1458,10 @@ compare_parameter (gfc_symbol *formal, gfc_expr *actual,
       && actual->ts.u.derived && actual->ts.u.derived->ts.is_iso_c)
     return 1;
 
-  if (formal->ts.type == BT_CLASS)
+  if (formal->ts.type == BT_CLASS && actual->ts.type == BT_DERIVED)
     /* Make sure the vtab symbol is present when
        the module variables are generated.  */
-    gfc_find_derived_vtab (formal->ts.u.derived);
+    gfc_find_derived_vtab (actual->ts.u.derived);
 
   if (actual->ts.type == BT_PROCEDURE)
     {
@@ -1584,7 +1619,8 @@ compare_parameter (gfc_symbol *formal, gfc_expr *actual,
   if (rank_check || ranks_must_agree
       || (formal->attr.pointer && actual->expr_type != EXPR_NULL)
       || (actual->rank != 0 && !(is_elemental || formal->attr.dimension))
-      || (actual->rank == 0 && formal->as->type == AS_ASSUMED_SHAPE)
+      || (actual->rank == 0 && formal->as->type == AS_ASSUMED_SHAPE
+         && actual->expr_type != EXPR_NULL)
       || (actual->rank == 0 && formal->attr.dimension
          && gfc_is_coindexed (actual)))
     {
@@ -1649,36 +1685,6 @@ compare_parameter (gfc_symbol *formal, gfc_expr *actual,
 }
 
 
-/* Given a symbol of a formal argument list and an expression, see if
-   the two are compatible as arguments.  Returns nonzero if
-   compatible, zero if not compatible.  */
-
-static int
-compare_parameter_protected (gfc_symbol *formal, gfc_expr *actual)
-{
-  if (actual->expr_type != EXPR_VARIABLE)
-    return 1;
-
-  if (!actual->symtree->n.sym->attr.is_protected)
-    return 1;
-
-  if (!actual->symtree->n.sym->attr.use_assoc)
-    return 1;
-
-  if (formal->attr.intent == INTENT_IN
-      || formal->attr.intent == INTENT_UNKNOWN)
-    return 1;
-
-  if (!actual->symtree->n.sym->attr.pointer)
-    return 0;
-
-  if (actual->symtree->n.sym->attr.pointer && formal->attr.pointer)
-    return 0;
-
-  return 1;
-}
-
-
 /* Returns the storage size of a symbol (formal argument) or
    zero if it cannot be determined.  */
 
@@ -1999,6 +2005,20 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
                       "call at %L", where);
          return 0;
        }
+
+      if (a->expr->expr_type == EXPR_NULL && !f->sym->attr.pointer
+         && (f->sym->attr.allocatable || !f->sym->attr.optional
+             || (gfc_option.allow_std & GFC_STD_F2008) == 0))
+       {
+         if (where && (f->sym->attr.allocatable || !f->sym->attr.optional))
+           gfc_error ("Unexpected NULL() intrinsic at %L to dummy '%s'",
+                      where, f->sym->name);
+         else if (where)
+           gfc_error ("Fortran 2008: Null pointer at %L to non-pointer "
+                      "dummy '%s'", where, f->sym->name);
+
+         return 0;
+       }
       
       if (!compare_parameter (f->sym, a->expr, ranks_must_agree,
                              is_elemental, where))
@@ -2113,6 +2133,17 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
          return 0;
        }
 
+      if (a->expr->expr_type != EXPR_NULL
+         && (gfc_option.allow_std & GFC_STD_F2008) == 0
+         && compare_pointer (f->sym, a->expr) == 2)
+       {
+         if (where)
+           gfc_error ("Fortran 2008: Non-pointer actual argument at %L to "
+                      "pointer dummy '%s'", &a->expr->where,f->sym->name);
+         return 0;
+       }
+       
+
       /* Fortran 2008, C1242.  */
       if (f->sym->attr.pointer && gfc_is_coindexed (a->expr))
        {
@@ -2174,27 +2205,20 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
        }
 
       /* Check intent = OUT/INOUT for definable actual argument.  */
-      if ((a->expr->expr_type != EXPR_VARIABLE
-          || (a->expr->symtree->n.sym->attr.flavor != FL_VARIABLE
-              && a->expr->symtree->n.sym->attr.flavor != FL_PROCEDURE))
-         && (f->sym->attr.intent == INTENT_OUT
-             || f->sym->attr.intent == INTENT_INOUT))
+      if ((f->sym->attr.intent == INTENT_OUT
+         || f->sym->attr.intent == INTENT_INOUT))
        {
-         if (where)
-           gfc_error ("Actual argument at %L must be definable as "
-                      "the dummy argument '%s' is INTENT = OUT/INOUT",
-                      &a->expr->where, f->sym->name);
-         return 0;
-       }
+         const char* context = (where
+                                ? _("actual argument to INTENT = OUT/INOUT")
+                                : NULL);
 
-      if (!compare_parameter_protected(f->sym, a->expr))
-       {
-         if (where)
-           gfc_error ("Actual argument at %L is use-associated with "
-                      "PROTECTED attribute and dummy argument '%s' is "
-                      "INTENT = OUT/INOUT",
-                      &a->expr->where,f->sym->name);
-         return 0;
+         if (f->sym->attr.pointer
+             && gfc_check_vardef_context (a->expr, true, context)
+                  == FAILURE)
+           return 0;
+         if (gfc_check_vardef_context (a->expr, false, context)
+               == FAILURE)
+           return 0;
        }
 
       if ((f->sym->attr.intent == INTENT_OUT