]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/fortran/frontend-passes.c
Update copyright years.
[thirdparty/gcc.git] / gcc / fortran / frontend-passes.c
index a6af96c43dbda332ee3b6f19ebdda05028818ab2..de11524ba14172d7d5273a6d1cfc529efd9e602e 100644 (file)
@@ -1,5 +1,5 @@
 /* Pass manager for Fortran front end.
-   Copyright (C) 2010-2018 Free Software Foundation, Inc.
+   Copyright (C) 2010-2020 Free Software Foundation, Inc.
    Contributed by Thomas König.
 
 This file is part of GCC.
@@ -54,10 +54,8 @@ static gfc_code * create_do_loop (gfc_expr *, gfc_expr *, gfc_expr *,
 static gfc_expr* check_conjg_transpose_variable (gfc_expr *, bool *,
                                                 bool *);
 static int call_external_blas (gfc_code **, int *, void *);
-static bool has_dimen_vector_ref (gfc_expr *);
 static int matmul_temp_args (gfc_code **, int *,void *data);
 static int index_interchange (gfc_code **, int*, void *);
-
 static bool is_fe_temp (gfc_expr *e);
 
 #ifdef CHECKING_P
@@ -94,6 +92,10 @@ static int forall_level;
 
 static bool in_omp_workshare;
 
+/* Keep track of whether we are within an OMP atomic.  */
+
+static bool in_omp_atomic;
+
 /* Keep track of whether we are within a WHERE statement.  */
 
 static bool in_where;
@@ -638,23 +640,27 @@ constant_string_length (gfc_expr *e)
        return gfc_copy_expr(length);
     }
 
-  /* Return length of substring, if constant. */
+  /* See if there is a substring. If it has a constant length, return
+     that and NULL otherwise.  */
   for (ref = e->ref; ref; ref = ref->next)
     {
-      if (ref->type == REF_SUBSTRING
-         && gfc_dep_difference (ref->u.ss.end, ref->u.ss.start, &value))
+      if (ref->type == REF_SUBSTRING)
        {
-         res = gfc_get_constant_expr (BT_INTEGER, gfc_charlen_int_kind,
-                                      &e->where);
+         if (gfc_dep_difference (ref->u.ss.end, ref->u.ss.start, &value))
+           {
+             res = gfc_get_constant_expr (BT_INTEGER, gfc_charlen_int_kind,
+                                          &e->where);
 
-         mpz_add_ui (res->value.integer, value, 1);
-         mpz_clear (value);
-         return res;
+             mpz_add_ui (res->value.integer, value, 1);
+             mpz_clear (value);
+             return res;
+           }
+         else
+           return NULL;
        }
     }
 
   /* Return length of char symbol, if constant.  */
-
   if (e->symtree && e->symtree->n.sym->ts.u.cl
       && e->symtree->n.sym->ts.u.cl->length
       && e->symtree->n.sym->ts.u.cl->length->expr_type == EXPR_CONSTANT)
@@ -911,9 +917,9 @@ cfe_expr_0 (gfc_expr **e, int *walk_subtrees,
   gfc_expr *newvar;
   gfc_expr **ei, **ej;
 
-  /* Don't do this optimization within OMP workshare or ASSOC lists.  */
+  /* Don't do this optimization within OMP workshare/atomic or ASSOC lists.  */
 
-  if (in_omp_workshare || in_assoc_list)
+  if (in_omp_workshare || in_omp_atomic || in_assoc_list)
     {
       *walk_subtrees = 0;
       return 0;
@@ -1462,6 +1468,7 @@ optimize_namespace (gfc_namespace *ns)
   iterator_level = 0;
   in_assoc_list = false;
   in_omp_workshare = false;
+  in_omp_atomic = false;
 
   if (flag_frontend_optimize)
     {
@@ -1769,6 +1776,10 @@ combine_array_constructor (gfc_expr *e)
   if (iterator_level > 0)
     return false;
 
+  /* WHERE also doesn't work.  */
+  if (in_where > 0)
+    return false;
+
   op1 = e->value.op.op1;
   op2 = e->value.op.op2;
 
@@ -1855,84 +1866,6 @@ combine_array_constructor (gfc_expr *e)
   return true;
 }
 
-/* Change (-1)**k into 1-ishift(iand(k,1),1) and
- 2**k into ishift(1,k) */
-
-static bool
-optimize_power (gfc_expr *e)
-{
-  gfc_expr *op1, *op2;
-  gfc_expr *iand, *ishft;
-
-  if (e->ts.type != BT_INTEGER)
-    return false;
-
-  op1 = e->value.op.op1;
-
-  if (op1 == NULL || op1->expr_type != EXPR_CONSTANT)
-    return false;
-
-  if (mpz_cmp_si (op1->value.integer, -1L) == 0)
-    {
-      gfc_free_expr (op1);
-
-      op2 = e->value.op.op2;
-
-      if (op2 == NULL)
-       return false;
-
-      iand = gfc_build_intrinsic_call (current_ns, GFC_ISYM_IAND,
-                                      "_internal_iand", e->where, 2, op2,
-                                      gfc_get_int_expr (e->ts.kind,
-                                                        &e->where, 1));
-
-      ishft = gfc_build_intrinsic_call (current_ns, GFC_ISYM_ISHFT,
-                                       "_internal_ishft", e->where, 2, iand,
-                                       gfc_get_int_expr (e->ts.kind,
-                                                         &e->where, 1));
-
-      e->value.op.op = INTRINSIC_MINUS;
-      e->value.op.op1 = gfc_get_int_expr (e->ts.kind, &e->where, 1);
-      e->value.op.op2 = ishft;
-      return true;
-    }
-  else if (mpz_cmp_si (op1->value.integer, 2L) == 0)
-    {
-      gfc_free_expr (op1);
-
-      op2 = e->value.op.op2;
-      if (op2 == NULL)
-       return false;
-
-      ishft = gfc_build_intrinsic_call (current_ns, GFC_ISYM_ISHFT,
-                                       "_internal_ishft", e->where, 2,
-                                       gfc_get_int_expr (e->ts.kind,
-                                                         &e->where, 1),
-                                       op2);
-      *e = *ishft;
-      return true;
-    }
-
-  else if (mpz_cmp_si (op1->value.integer, 1L) == 0)
-    {
-      op2 = e->value.op.op2;
-      if (op2 == NULL)
-       return false;
-
-      gfc_free_expr (op1);
-      gfc_free_expr (op2);
-
-      e->expr_type = EXPR_CONSTANT;
-      e->value.op.op1 = NULL;
-      e->value.op.op2 = NULL;
-      mpz_init_set_si (e->value.integer, 1);
-      /* Typespec and location are still OK.  */
-      return true;
-    }
-
-  return false;
-}
-
 /* Recursive optimization of operators.  */
 
 static bool
@@ -1993,9 +1926,6 @@ optimize_op (gfc_expr *e)
     case INTRINSIC_DIVIDE:
       return combine_array_constructor (e) || changed;
 
-    case INTRINSIC_POWER:
-      return optimize_power (e);
-
     default:
       break;
     }
@@ -2592,7 +2522,12 @@ insert_index (gfc_expr *e, gfc_symbol *sym, mpz_t val, mpz_t ret)
   data.sym = sym;
   mpz_init_set (data.val, val);
   gfc_expr_walker (&n, callback_insert_index, (void *) &data);
+
+  /* Suppress errors here - we could get errors here such as an
+     out of bounds access for arrays, see PR 90563.  */
+  gfc_push_suppress_errors ();
   gfc_simplify_expr (n, 0);
+  gfc_pop_suppress_errors ();
 
   if (n->expr_type == EXPR_CONSTANT)
     {
@@ -2630,6 +2565,12 @@ do_subscript (gfc_expr **e)
   if (in_assoc_list)
     return 0;
 
+  /* We already warned about this.  */
+  if (v->do_not_warn)
+    return 0;
+
+  v->do_not_warn = 1;
+
   for (ref = v->ref; ref; ref = ref->next)
     {
       if (ref->type == REF_ARRAY && ref->u.ar.type == AR_ELEMENT)
@@ -2642,6 +2583,7 @@ do_subscript (gfc_expr **e)
              bool have_do_start, have_do_end;
              bool error_not_proven;
              int warn;
+             int sgn;
 
              dl = lp->c;
              if (dl == NULL)
@@ -2670,7 +2612,16 @@ do_subscript (gfc_expr **e)
                 Do not warn in this case.  */
 
              if (dl->ext.iterator->step->expr_type == EXPR_CONSTANT)
-               mpz_init_set (do_step, dl->ext.iterator->step->value.integer);
+               {
+                 sgn = mpz_cmp_ui (dl->ext.iterator->step->value.integer, 0);
+                 /* This can happen, but then the error has been
+                    reported previously.  */
+                 if (sgn == 0)
+                   continue;
+
+                 mpz_init_set (do_step, dl->ext.iterator->step->value.integer);
+               }
+
              else
                continue;
 
@@ -2682,7 +2633,6 @@ do_subscript (gfc_expr **e)
              else
                have_do_start = false;
 
-
              if (dl->ext.iterator->end->expr_type == EXPR_CONSTANT)
                {
                  have_do_end = true;
@@ -2694,6 +2644,16 @@ do_subscript (gfc_expr **e)
              if (!have_do_start && !have_do_end)
                return 0;
 
+             /* No warning inside a zero-trip loop.  */
+             if (have_do_start && have_do_end)
+               {
+                 int cmp;
+
+                 cmp = mpz_cmp (do_end, do_start);
+                 if ((sgn > 0 && cmp < 0) || (sgn < 0 && cmp > 0))
+                   break;
+               }
+
              /* May have to correct the end value if the step does not equal
                 one.  */
              if (have_do_start && have_do_end && mpz_cmp_ui (do_step, 1) != 0)
@@ -2835,6 +2795,12 @@ static void
 doloop_warn (gfc_namespace *ns)
 {
   gfc_code_walker (&ns->code, doloop_code, do_function, NULL);
+
+  for (ns = ns->contained; ns; ns = ns->sibling)
+    {
+      if (ns->code == NULL || ns->code->op != EXEC_BLOCK)
+       doloop_warn (ns);
+    }
 }
 
 /* This selction deals with inlining calls to MATMUL.  */
@@ -2857,7 +2823,7 @@ matmul_to_var_expr (gfc_expr **ep, int *walk_subtrees ATTRIBUTE_UNUSED,
     return 0;
 
   if (forall_level > 0 || iterator_level > 0 || in_omp_workshare
-      || in_where || in_assoc_list)
+      || in_omp_atomic || in_where || in_assoc_list)
     return 0;
 
   /* Check if this is already in the form c = matmul(a,b).  */
@@ -2919,7 +2885,7 @@ matmul_temp_args (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
     return 0;
 
   if (forall_level > 0 || iterator_level > 0 || in_omp_workshare
-      || in_where)
+      || in_omp_atomic || in_where)
     return 0;
 
   /* This has some duplication with inline_matmul_assign.  This
@@ -2941,7 +2907,7 @@ matmul_temp_args (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
     {
       if (matrix_a->expr_type == EXPR_VARIABLE
          && (gfc_check_dependency (matrix_a, expr1, true)
-             || has_dimen_vector_ref (matrix_a)))
+             || gfc_has_dimen_vector_ref (matrix_a)))
        a_tmp = true;
     }
   else
@@ -2954,7 +2920,7 @@ matmul_temp_args (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
     {
       if (matrix_b->expr_type == EXPR_VARIABLE
          && (gfc_check_dependency (matrix_b, expr1, true)
-             || has_dimen_vector_ref (matrix_b)))
+             || gfc_has_dimen_vector_ref (matrix_b)))
        b_tmp = true;
     }
   else
@@ -3754,8 +3720,8 @@ scalarized_expr (gfc_expr *e_in, gfc_expr **index, int count_index)
 
 /* Helper function to check for a dimen vector as subscript.  */
 
-static bool
-has_dimen_vector_ref (gfc_expr *e)
+bool
+gfc_has_dimen_vector_ref (gfc_expr *e)
 {
   gfc_array_ref *ar;
   int i;
@@ -3816,11 +3782,14 @@ check_conjg_transpose_variable (gfc_expr *e, bool *conjg, bool *transpose)
 
 /* Macros for unified error messages.  */
 
-#define B_ERROR(n) _("Incorrect extent in argument B in MATMUL intrinsic in " \
-                    "dimension " #n ": is %ld, should be %ld")
+#define B_ERROR_1 _("Incorrect extent in argument B in MATMUL intrinsic in " \
+                    "dimension 1: is %ld, should be %ld")
+
+#define C_ERROR_1 _("Array bound mismatch for dimension 1 of array " \
+                   "(%ld/%ld)")
 
-#define C_ERROR(n) _("Array bound mismatch for dimension " #n " of array " \
-                    "(%ld/%ld)")
+#define C_ERROR_2 _("Array bound mismatch for dimension 2 of array " \
+                   "(%ld/%ld)")
 
 
 /* Inline assignments of the form c = matmul(a,b).
@@ -3884,7 +3853,7 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
   /* For now don't do anything in OpenMP workshare, it confuses
      its translation, which expects only the allowed statements in there.
      We should figure out how to parallelize this eventually.  */
-  if (in_omp_workshare)
+  if (in_omp_workshare || in_omp_atomic)
     return 0;
 
   expr1 = co->expr1;
@@ -3908,8 +3877,8 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
   if (matrix_b == NULL)
     return 0;
 
-  if (has_dimen_vector_ref (expr1) || has_dimen_vector_ref (matrix_a)
-      || has_dimen_vector_ref (matrix_b))
+  if (gfc_has_dimen_vector_ref (expr1) || gfc_has_dimen_vector_ref (matrix_a)
+      || gfc_has_dimen_vector_ref (matrix_b))
     return 0;
 
   /* We do not handle data dependencies yet.  */
@@ -4049,7 +4018,7 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
 
          b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
          a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
-         test = runtime_error_ne (b1, a2, B_ERROR(1));
+         test = runtime_error_ne (b1, a2, B_ERROR_1);
          *next_code_point = test;
          next_code_point = &test->next;
 
@@ -4057,7 +4026,7 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
            {
              c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
              a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
-             test = runtime_error_ne (c1, a1, C_ERROR(1));
+             test = runtime_error_ne (c1, a1, C_ERROR_1);
              *next_code_point = test;
              next_code_point = &test->next;
            }
@@ -4067,7 +4036,7 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
 
          b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
          a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
-         test = runtime_error_ne (b1, a1, B_ERROR(1));
+         test = runtime_error_ne (b1, a1, B_ERROR_1);
          *next_code_point = test;
          next_code_point = &test->next;
 
@@ -4075,7 +4044,7 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
            {
              c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
              b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
-             test = runtime_error_ne (c1, b2, C_ERROR(1));
+             test = runtime_error_ne (c1, b2, C_ERROR_1);
              *next_code_point = test;
              next_code_point = &test->next;
            }
@@ -4085,7 +4054,7 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
 
          b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
          a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
-         test = runtime_error_ne (b1, a2, B_ERROR(1));
+         test = runtime_error_ne (b1, a2, B_ERROR_1);
          *next_code_point = test;
          next_code_point = &test->next;
 
@@ -4093,13 +4062,13 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
            {
              c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
              a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
-             test = runtime_error_ne (c1, a1, C_ERROR(1));
+             test = runtime_error_ne (c1, a1, C_ERROR_1);
              *next_code_point = test;
              next_code_point = &test->next;
 
              c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
              b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
-             test = runtime_error_ne (c2, b2, C_ERROR(2));
+             test = runtime_error_ne (c2, b2, C_ERROR_2);
              *next_code_point = test;
              next_code_point = &test->next;
            }
@@ -4110,7 +4079,7 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
          b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
          a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
          /* matrix_b is transposed, hence dimension 1 for the error message.  */
-         test = runtime_error_ne (b2, a2, B_ERROR(1));
+         test = runtime_error_ne (b2, a2, B_ERROR_1);
          *next_code_point = test;
          next_code_point = &test->next;
 
@@ -4118,13 +4087,13 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
            {
              c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
              a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
-             test = runtime_error_ne (c1, a1, C_ERROR(1));
+             test = runtime_error_ne (c1, a1, C_ERROR_1);
              *next_code_point = test;
              next_code_point = &test->next;
 
              c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
              b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
-             test = runtime_error_ne (c2, b1, C_ERROR(2));
+             test = runtime_error_ne (c2, b1, C_ERROR_2);
              *next_code_point = test;
              next_code_point = &test->next;
            }
@@ -4134,7 +4103,7 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
 
          b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
          a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
-         test = runtime_error_ne (b1, a1, B_ERROR(1));
+         test = runtime_error_ne (b1, a1, B_ERROR_1);
          *next_code_point = test;
          next_code_point = &test->next;
 
@@ -4142,13 +4111,13 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
            {
              c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
              a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
-             test = runtime_error_ne (c1, a2, C_ERROR(1));
+             test = runtime_error_ne (c1, a2, C_ERROR_1);
              *next_code_point = test;
              next_code_point = &test->next;
 
              c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
              b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
-             test = runtime_error_ne (c2, b2, C_ERROR(2));
+             test = runtime_error_ne (c2, b2, C_ERROR_2);
              *next_code_point = test;
              next_code_point = &test->next;
            }
@@ -4421,7 +4390,7 @@ call_external_blas (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
   /* For now don't do anything in OpenMP workshare, it confuses
      its translation, which expects only the allowed statements in there. */
 
-  if (in_omp_workshare)
+  if (in_omp_workshare || in_omp_atomic)
     return 0;
 
   expr1 = co->expr1;
@@ -4551,7 +4520,7 @@ call_external_blas (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
        case A2B2:
          b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
          a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
-         test = runtime_error_ne (b1, a2, B_ERROR(1));
+         test = runtime_error_ne (b1, a2, B_ERROR_1);
          *next_code_point = test;
          next_code_point = &test->next;
 
@@ -4559,13 +4528,13 @@ call_external_blas (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
            {
              c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
              a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
-             test = runtime_error_ne (c1, a1, C_ERROR(1));
+             test = runtime_error_ne (c1, a1, C_ERROR_1);
              *next_code_point = test;
              next_code_point = &test->next;
 
              c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
              b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
-             test = runtime_error_ne (c2, b2, C_ERROR(2));
+             test = runtime_error_ne (c2, b2, C_ERROR_2);
              *next_code_point = test;
              next_code_point = &test->next;
            }
@@ -4576,7 +4545,7 @@ call_external_blas (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
          b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
          a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
          /* matrix_b is transposed, hence dimension 1 for the error message.  */
-         test = runtime_error_ne (b2, a2, B_ERROR(1));
+         test = runtime_error_ne (b2, a2, B_ERROR_1);
          *next_code_point = test;
          next_code_point = &test->next;
 
@@ -4584,13 +4553,13 @@ call_external_blas (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
            {
              c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
              a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
-             test = runtime_error_ne (c1, a1, C_ERROR(1));
+             test = runtime_error_ne (c1, a1, C_ERROR_1);
              *next_code_point = test;
              next_code_point = &test->next;
 
              c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
              b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
-             test = runtime_error_ne (c2, b1, C_ERROR(2));
+             test = runtime_error_ne (c2, b1, C_ERROR_2);
              *next_code_point = test;
              next_code_point = &test->next;
            }
@@ -4600,7 +4569,7 @@ call_external_blas (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
 
          b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
          a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
-         test = runtime_error_ne (b1, a1, B_ERROR(1));
+         test = runtime_error_ne (b1, a1, B_ERROR_1);
          *next_code_point = test;
          next_code_point = &test->next;
 
@@ -4608,13 +4577,13 @@ call_external_blas (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
            {
              c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
              a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
-             test = runtime_error_ne (c1, a2, C_ERROR(1));
+             test = runtime_error_ne (c1, a2, C_ERROR_1);
              *next_code_point = test;
              next_code_point = &test->next;
 
              c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
              b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
-             test = runtime_error_ne (c2, b2, C_ERROR(2));
+             test = runtime_error_ne (c2, b2, C_ERROR_2);
              *next_code_point = test;
              next_code_point = &test->next;
            }
@@ -4623,7 +4592,7 @@ call_external_blas (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
        case A2TB2T:
          b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
          a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
-         test = runtime_error_ne (b2, a1, B_ERROR(1));
+         test = runtime_error_ne (b2, a1, B_ERROR_1);
          *next_code_point = test;
          next_code_point = &test->next;
 
@@ -4631,13 +4600,13 @@ call_external_blas (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
            {
              c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
              a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
-             test = runtime_error_ne (c1, a2, C_ERROR(1));
+             test = runtime_error_ne (c1, a2, C_ERROR_1);
              *next_code_point = test;
              next_code_point = &test->next;
 
              c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
              b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
-             test = runtime_error_ne (c2, b1, C_ERROR(2));
+             test = runtime_error_ne (c2, b1, C_ERROR_2);
              *next_code_point = test;
              next_code_point = &test->next;
            }
@@ -4671,6 +4640,7 @@ call_external_blas (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
   call->symtree->n.sym->attr.procedure = 1;
   call->symtree->n.sym->attr.flavor = FL_PROCEDURE;
   call->resolved_sym = call->symtree->n.sym;
+  gfc_commit_symbol (call->resolved_sym);
 
   /* Argument TRANSA.  */
   next = gfc_get_actual_arglist ();
@@ -5037,6 +5007,7 @@ gfc_expr_walker (gfc_expr **e, walk_expr_fn_t exprfn, void *data)
                    break;
 
                  case REF_COMPONENT:
+                 case REF_INQUIRY:
                    break;
                  }
              }
@@ -5081,6 +5052,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
          gfc_code *co;
          gfc_association_list *alist;
          bool saved_in_omp_workshare;
+         bool saved_in_omp_atomic;
          bool saved_in_where;
 
          /* There might be statement insertions before the current code,
@@ -5088,6 +5060,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
 
          co = *c;
          saved_in_omp_workshare = in_omp_workshare;
+         saved_in_omp_atomic = in_omp_atomic;
          saved_in_where = in_where;
 
          switch (co->op)
@@ -5285,6 +5258,10 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
              WALK_SUBEXPR (co->ext.dt->extra_comma);
              break;
 
+           case EXEC_OMP_ATOMIC:
+             in_omp_atomic = true;
+             break;
+
            case EXEC_OMP_PARALLEL:
            case EXEC_OMP_PARALLEL_DO:
            case EXEC_OMP_PARALLEL_DO_SIMD:
@@ -5402,8 +5379,139 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
            select_level --;
 
          in_omp_workshare = saved_in_omp_workshare;
+         in_omp_atomic = saved_in_omp_atomic;
          in_where = saved_in_where;
        }
     }
   return 0;
 }
+
+/* As a post-resolution step, check that all global symbols which are
+   not declared in the source file match in their call signatures.
+   We do this by looping over the code (and expressions). The first call
+   we happen to find is assumed to be canonical.  */
+
+
+/* Common tests for argument checking for both functions and subroutines.  */
+
+static int
+check_externals_procedure (gfc_symbol *sym, locus *loc,
+                          gfc_actual_arglist *actual)
+{
+  gfc_gsymbol *gsym;
+  gfc_symbol *def_sym = NULL;
+
+ if (sym == NULL || sym->attr.is_bind_c)
+    return 0;
+
+  if (sym->attr.proc != PROC_EXTERNAL && sym->attr.proc != PROC_UNKNOWN)
+    return 0;
+
+  if (sym->attr.if_source == IFSRC_IFBODY || sym->attr.if_source == IFSRC_DECL)
+    return 0;
+
+  gsym = gfc_find_gsymbol (gfc_gsym_root, sym->name);
+  if (gsym == NULL)
+    return 0;
+
+  if (gsym->ns)
+    gfc_find_symbol (sym->name, gsym->ns, 0, &def_sym);
+
+  if (def_sym)
+    {
+      gfc_compare_actual_formal (&actual, def_sym->formal, 0, 0, 0, loc);
+      return 0;
+    }
+
+  /* First time we have seen this procedure called. Let's create an
+     "interface" from the call and put it into a new namespace.  */
+  gfc_namespace *save_ns;
+  gfc_symbol *new_sym;
+
+  gsym->where = *loc;
+  save_ns = gfc_current_ns;
+  gsym->ns = gfc_get_namespace (gfc_current_ns, 0);
+  gsym->ns->proc_name = sym;
+
+  gfc_get_symbol (sym->name, gsym->ns, &new_sym);
+  gcc_assert (new_sym);
+  new_sym->attr = sym->attr;
+  new_sym->attr.if_source = IFSRC_DECL;
+  gfc_current_ns = gsym->ns;
+
+  gfc_get_formal_from_actual_arglist (new_sym, actual);
+  gfc_current_ns = save_ns;
+
+  return 0;
+
+}
+
+/* Callback for calls of external routines.  */
+
+static int
+check_externals_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
+                     void *data ATTRIBUTE_UNUSED)
+{
+  gfc_code *co = *c;
+  gfc_symbol *sym;
+  locus *loc;
+  gfc_actual_arglist *actual;
+
+  if (co->op != EXEC_CALL)
+    return 0;
+
+  sym = co->resolved_sym;
+  loc = &co->loc;
+  actual = co->ext.actual;
+
+  return check_externals_procedure (sym, loc, actual);
+
+}
+
+/* Callback for external functions.  */
+
+static int
+check_externals_expr (gfc_expr **ep, int *walk_subtrees ATTRIBUTE_UNUSED,
+                     void *data ATTRIBUTE_UNUSED)
+{
+  gfc_expr *e = *ep;
+  gfc_symbol *sym;
+  locus *loc;
+  gfc_actual_arglist *actual;
+
+  if (e->expr_type != EXPR_FUNCTION)
+    return 0;
+
+  sym = e->value.function.esym;
+  if (sym == NULL)
+    return 0;
+
+  loc = &e->where;
+  actual = e->value.function.actual;
+
+  return check_externals_procedure (sym, loc, actual);
+}
+
+/* Called routine.  */
+
+void
+gfc_check_externals (gfc_namespace *ns)
+{
+
+  gfc_clear_error ();
+
+  /* Turn errors into warnings if the user indicated this.  */
+
+  if (!pedantic && flag_allow_argument_mismatch)
+    gfc_errors_to_warnings (true);
+
+  gfc_code_walker (&ns->code, check_externals_code, check_externals_expr, NULL);
+
+  for (ns = ns->contained; ns; ns = ns->sibling)
+    {
+      if (ns->code == NULL || ns->code->op != EXEC_BLOCK)
+       gfc_check_externals (ns);
+    }
+
+  gfc_errors_to_warnings (false);
+}