gfortran.h (gfc_option_t): Remove warn_aliasing,
[gcc.git] / gcc / fortran / frontend-passes.c
index b8288a850438f16fb1b70c53bf18b7dac8d8dfa6..799d2fedddc210ca34972423381b3754e9fbd363 100644 (file)
@@ -1,5 +1,5 @@
 /* Pass manager for Fortran front end.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010-2014 Free Software Foundation, Inc.
    Contributed by Thomas König.
 
 This file is part of GCC.
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
 #include "gfortran.h"
 #include "arith.h"
 #include "flags.h"
@@ -36,44 +37,81 @@ static bool optimize_op (gfc_expr *);
 static bool optimize_comparison (gfc_expr *, gfc_intrinsic_op);
 static bool optimize_trim (gfc_expr *);
 static bool optimize_lexical_comparison (gfc_expr *);
+static void optimize_minmaxloc (gfc_expr **);
+static bool is_empty_string (gfc_expr *e);
+static void doloop_warn (gfc_namespace *);
+static void optimize_reduction (gfc_namespace *);
+static int callback_reduction (gfc_expr **, int *, void *);
 
 /* How deep we are inside an argument list.  */
 
 static int count_arglist;
 
-/* Pointer to an array of gfc_expr ** we operate on, plus its size
-   and counter.  */
+/* Vector of gfc_expr ** we operate on.  */
 
-static gfc_expr ***expr_array;
-static int expr_size, expr_count;
+static vec<gfc_expr **> expr_array;
 
 /* Pointer to the gfc_code we currently work on - to be able to insert
-   a statement before.  */
+   a block before the statement.  */
 
 static gfc_code **current_code;
 
+/* Pointer to the block to be inserted, and the statement we are
+   changing within the block.  */
+
+static gfc_code *inserted_block, **changed_statement;
+
 /* The namespace we are currently dealing with.  */
 
-gfc_namespace *current_ns;
+static gfc_namespace *current_ns;
+
+/* If we are within any forall loop.  */
+
+static int forall_level;
+
+/* Keep track of whether we are within an OMP workshare.  */
+
+static bool in_omp_workshare;
+
+/* Keep track of iterators for array constructors.  */
+
+static int iterator_level;
+
+/* Keep track of DO loop levels.  */
+
+static vec<gfc_code *> doloop_list;
+
+static int doloop_level;
+
+/* Vector of gfc_expr * to keep track of DO loops.  */
+
+struct my_struct *evec;
+
+/* Keep track of association lists.  */
+
+static bool in_assoc_list;
 
-/* Entry point - run all passes for a namespace.  So far, only an
-   optimization pass is run.  */
+/* Entry point - run all passes for a namespace.  */
 
 void
 gfc_run_passes (gfc_namespace *ns)
 {
+
+  /* Warn about dubious DO loops where the index might
+     change.  */
+
+  doloop_level = 0;
+  doloop_warn (ns);
+  doloop_list.release ();
+
   if (gfc_option.flag_frontend_optimize)
     {
-      expr_size = 20;
-      expr_array = XNEWVEC(gfc_expr **, expr_size);
-
       optimize_namespace (ns);
+      optimize_reduction (ns);
       if (gfc_option.dump_fortran_optimized)
        gfc_dump_parse_tree (ns, stdout);
 
-      /* FIXME: The following should be XDELETEVEC(expr_array);
-      but we cannot do that because it depends on free.  */
-      gfc_free (expr_array);
+      expr_array.release ();
     }
 }
 
@@ -95,6 +133,10 @@ optimize_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
   else
     count_arglist = 0;
 
+  current_code = c;
+  inserted_block = NULL;
+  changed_statement = NULL;
+
   if (op == EXEC_ASSIGN)
     optimize_assignment (*c);
   return 0;
@@ -126,49 +168,221 @@ optimize_expr (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
   if ((*e)->expr_type == EXPR_OP && optimize_op (*e))
     gfc_simplify_expr (*e, 0);
 
+  if ((*e)->expr_type == EXPR_FUNCTION && (*e)->value.function.isym)
+    switch ((*e)->value.function.isym->id)
+      {
+      case GFC_ISYM_MINLOC:
+      case GFC_ISYM_MAXLOC:
+       optimize_minmaxloc (e);
+       break;
+      default:
+       break;
+      }
+
   if (function_expr)
     count_arglist --;
 
   return 0;
 }
 
+/* Auxiliary function to handle the arguments to reduction intrnisics.  If the
+   function is a scalar, just copy it; otherwise returns the new element, the
+   old one can be freed.  */
+
+static gfc_expr *
+copy_walk_reduction_arg (gfc_constructor *c, gfc_expr *fn)
+{
+  gfc_expr *fcn, *e = c->expr;
+
+  fcn = gfc_copy_expr (e);
+  if (c->iterator)
+    {
+      gfc_constructor_base newbase;
+      gfc_expr *new_expr;
+      gfc_constructor *new_c;
+
+      newbase = NULL;
+      new_expr = gfc_get_expr ();
+      new_expr->expr_type = EXPR_ARRAY;
+      new_expr->ts = e->ts;
+      new_expr->where = e->where;
+      new_expr->rank = 1;
+      new_c = gfc_constructor_append_expr (&newbase, fcn, &(e->where));
+      new_c->iterator = c->iterator;
+      new_expr->value.constructor = newbase;
+      c->iterator = NULL;
+
+      fcn = new_expr;
+    }
+
+  if (fcn->rank != 0)
+    {
+      gfc_isym_id id = fn->value.function.isym->id;
+
+      if (id == GFC_ISYM_SUM || id == GFC_ISYM_PRODUCT)
+       fcn = gfc_build_intrinsic_call (current_ns, id,
+                                       fn->value.function.isym->name,
+                                       fn->where, 3, fcn, NULL, NULL);
+      else if (id == GFC_ISYM_ANY || id == GFC_ISYM_ALL)
+       fcn = gfc_build_intrinsic_call (current_ns, id,
+                                       fn->value.function.isym->name,
+                                       fn->where, 2, fcn, NULL);
+      else
+       gfc_internal_error ("Illegal id in copy_walk_reduction_arg");
+
+      fcn->symtree->n.sym->attr.access = ACCESS_PRIVATE;
+    }
+
+  return fcn;
+}
+
+/* Callback function for optimzation of reductions to scalars.  Transform ANY
+   ([f1,f2,f3, ...]) to f1 .or. f2 .or. f3 .or. ..., with ANY, SUM and PRODUCT
+   correspondingly.  Handly only the simple cases without MASK and DIM.  */
+
+static int
+callback_reduction (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
+                   void *data ATTRIBUTE_UNUSED)
+{
+  gfc_expr *fn, *arg;
+  gfc_intrinsic_op op;
+  gfc_isym_id id;
+  gfc_actual_arglist *a;
+  gfc_actual_arglist *dim;
+  gfc_constructor *c;
+  gfc_expr *res, *new_expr;
+  gfc_actual_arglist *mask;
+
+  fn = *e;
+
+  if (fn->rank != 0 || fn->expr_type != EXPR_FUNCTION
+      || fn->value.function.isym == NULL)
+    return 0;
+
+  id = fn->value.function.isym->id;
+
+  if (id != GFC_ISYM_SUM && id != GFC_ISYM_PRODUCT
+      && id != GFC_ISYM_ANY && id != GFC_ISYM_ALL)
+    return 0;
+
+  a = fn->value.function.actual;
+
+  /* Don't handle MASK or DIM.  */
+
+  dim = a->next;
+
+  if (dim->expr != NULL)
+    return 0;
+
+  if (id == GFC_ISYM_SUM || id == GFC_ISYM_PRODUCT)
+    {
+      mask = dim->next;
+      if ( mask->expr != NULL)
+       return 0;
+    }
+
+  arg = a->expr;
+
+  if (arg->expr_type != EXPR_ARRAY)
+    return 0;
+
+  switch (id)
+    {
+    case GFC_ISYM_SUM:
+      op = INTRINSIC_PLUS;
+      break;
+
+    case GFC_ISYM_PRODUCT:
+      op = INTRINSIC_TIMES;
+      break;
+
+    case GFC_ISYM_ANY:
+      op = INTRINSIC_OR;
+      break;
+
+    case GFC_ISYM_ALL:
+      op = INTRINSIC_AND;
+      break;
+
+    default:
+      return 0;
+    }
+
+  c = gfc_constructor_first (arg->value.constructor);
+
+  /* Don't do any simplififcation if we have
+     - no element in the constructor or
+     - only have a single element in the array which contains an
+     iterator.  */
+
+  if (c == NULL)
+    return 0;
+
+  res = copy_walk_reduction_arg (c, fn);
+
+  c = gfc_constructor_next (c);
+  while (c)
+    {
+      new_expr = gfc_get_expr ();
+      new_expr->ts = fn->ts;
+      new_expr->expr_type = EXPR_OP;
+      new_expr->rank = fn->rank;
+      new_expr->where = fn->where;
+      new_expr->value.op.op = op;
+      new_expr->value.op.op1 = res;
+      new_expr->value.op.op2 = copy_walk_reduction_arg (c, fn);
+      res = new_expr;
+      c = gfc_constructor_next (c);
+    }
+
+  gfc_simplify_expr (res, 0);
+  *e = res;
+  gfc_free_expr (fn);
+
+  return 0;
+}
 
 /* Callback function for common function elimination, called from cfe_expr_0.
-   Put all eligible function expressions into expr_array.  We can't do
-   allocatable functions.  */
+   Put all eligible function expressions into expr_array.  */
 
 static int
 cfe_register_funcs (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
          void *data ATTRIBUTE_UNUSED)
 {
 
-  /* FIXME - there is a bug in the insertion code for DO loops.  Bail
-     out here.  */
+  if ((*e)->expr_type != EXPR_FUNCTION)
+    return 0;
 
-  if ((*current_code)->op == EXEC_DO)
+  /* We don't do character functions with unknown charlens.  */
+  if ((*e)->ts.type == BT_CHARACTER 
+      && ((*e)->ts.u.cl == NULL || (*e)->ts.u.cl->length == NULL
+         || (*e)->ts.u.cl->length->expr_type != EXPR_CONSTANT))
     return 0;
 
-  if ((*e)->expr_type != EXPR_FUNCTION)
+  /* We don't do function elimination within FORALL statements, it can
+     lead to wrong-code in certain circumstances.  */
+
+  if (forall_level > 0)
     return 0;
 
-  /* We don't do character functions (yet).  */
-  if ((*e)->ts.type == BT_CHARACTER)
+  /* Function elimination inside an iterator could lead to functions which
+     depend on iterator variables being moved outside.  FIXME: We should check
+     if the functions do indeed depend on the iterator variable.  */
+
+  if (iterator_level > 0)
     return 0;
 
-  /* If we don't know the shape at compile time, we do not create a temporary
-     variable to hold the intermediate result.  FIXME: Change this later when
-     allocation on assignment works for intrinsics.  */
+  /* If we don't know the shape at compile time, we create an allocatable
+     temporary variable to hold the intermediate result, but only if
+     allocation on assignment is active.  */
 
-  if ((*e)->rank > 0 && (*e)->shape == NULL)
+  if ((*e)->rank > 0 && (*e)->shape == NULL && !gfc_option.flag_realloc_lhs)
     return 0;
   
   /* Skip the test for pure functions if -faggressive-function-elimination
      is specified.  */
   if ((*e)->value.function.esym)
     {
-      if ((*e)->value.function.esym->attr.allocatable)
-       return 0;
-
       /* Don't create an array temporary for elemental functions.  */
       if ((*e)->value.function.esym->attr.elemental && (*e)->rank > 0)
        return 0;
@@ -184,9 +398,10 @@ cfe_register_funcs (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
   if ((*e)->value.function.isym)
     {
       /* Conversions are handled on the fly by the middle end,
-        transpose during trans-* stages.  */
+        transpose during trans-* stages and TRANSFER by the middle end.  */
       if ((*e)->value.function.isym->id == GFC_ISYM_CONVERSION
-         || (*e)->value.function.isym->id == GFC_ISYM_TRANSPOSE)
+         || (*e)->value.function.isym->id == GFC_ISYM_TRANSFER
+         || gfc_inline_intrinsic_function_p (*e))
        return 0;
 
       /* Don't create an array temporary for elemental functions,
@@ -199,19 +414,30 @@ cfe_register_funcs (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
        return 0;
     }
 
-  if (expr_count >= expr_size)
-    {
-      expr_size += expr_size;
-      expr_array = XRESIZEVEC(gfc_expr **, expr_array, expr_size);
-    }
-  expr_array[expr_count] = e;
-  expr_count ++;
+  expr_array.safe_push (e);
   return 0;
 }
 
+/* Auxiliary function to check if an expression is a temporary created by
+   create var.  */
+
+static bool
+is_fe_temp (gfc_expr *e)
+{
+  if (e->expr_type != EXPR_VARIABLE)
+    return false;
+
+  return e->symtree->n.sym->attr.fe_temp;
+}
+
+
 /* Returns a new expression (a variable) to be used in place of the old one,
-   with an an assignment statement before the current statement to set
-   the value of the variable.  */
+   with an assignment statement before the current statement to set
+   the value of the variable. Creates a new BLOCK for the statement if
+   that hasn't already been done and puts the statement, plus the
+   newly created variables, in that block.  Special cases:  If the
+   expression is constant or a temporary which has already
+   been created, just copy it.  */
 
 static gfc_expr*
 create_var (gfc_expr * e)
@@ -222,35 +448,87 @@ create_var (gfc_expr * e)
   gfc_symbol *symbol;
   gfc_expr *result;
   gfc_code *n;
+  gfc_namespace *ns;
   int i;
 
+  if (e->expr_type == EXPR_CONSTANT || is_fe_temp (e))
+    return gfc_copy_expr (e);
+
+  /* If the block hasn't already been created, do so.  */
+  if (inserted_block == NULL)
+    {
+      inserted_block = XCNEW (gfc_code);
+      inserted_block->op = EXEC_BLOCK;
+      inserted_block->loc = (*current_code)->loc;
+      ns = gfc_build_block_ns (current_ns);
+      inserted_block->ext.block.ns = ns;
+      inserted_block->ext.block.assoc = NULL;
+
+      ns->code = *current_code;
+
+      /* If the statement has a label,  make sure it is transferred to
+        the newly created block.  */
+
+      if ((*current_code)->here) 
+       {
+         inserted_block->here = (*current_code)->here;
+         (*current_code)->here = NULL;
+       }
+
+      inserted_block->next = (*current_code)->next;
+      changed_statement = &(inserted_block->ext.block.ns->code);
+      (*current_code)->next = NULL;
+      /* Insert the BLOCK at the right position.  */
+      *current_code = inserted_block;
+      ns->parent = current_ns;
+    }
+  else
+    ns = inserted_block->ext.block.ns;
+
   sprintf(name, "__var_%d",num++);
-  if (gfc_get_sym_tree (name, current_ns, &symtree, false) != 0)
+  if (gfc_get_sym_tree (name, ns, &symtree, false) != 0)
     gcc_unreachable ();
 
   symbol = symtree->n.sym;
   symbol->ts = e->ts;
-  symbol->as = gfc_get_array_spec ();
-  symbol->as->rank = e->rank;
-  symbol->as->type = AS_EXPLICIT;
-  for (i=0; i<e->rank; i++)
+
+  if (e->rank > 0)
     {
-      gfc_expr *p, *q;
+      symbol->as = gfc_get_array_spec ();
+      symbol->as->rank = e->rank;
+
+      if (e->shape == NULL)
+       {
+         /* We don't know the shape at compile time, so we use an
+            allocatable.  */
+         symbol->as->type = AS_DEFERRED;
+         symbol->attr.allocatable = 1;
+       }
+      else
+       {
+         symbol->as->type = AS_EXPLICIT;
+         /* Copy the shape.  */
+         for (i=0; i<e->rank; i++)
+           {
+             gfc_expr *p, *q;
       
-      p = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind,
-                                &(e->where));
-      mpz_set_si (p->value.integer, 1);
-      symbol->as->lower[i] = p;
-         
-      q = gfc_get_constant_expr (BT_INTEGER, gfc_index_integer_kind,
-                                &(e->where));
-      mpz_set (q->value.integer, e->shape[i]);
-      symbol->as->upper[i] = q;
+             p = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind,
+                                        &(e->where));
+             mpz_set_si (p->value.integer, 1);
+             symbol->as->lower[i] = p;
+             
+             q = gfc_get_constant_expr (BT_INTEGER, gfc_index_integer_kind,
+                                        &(e->where));
+             mpz_set (q->value.integer, e->shape[i]);
+             symbol->as->upper[i] = q;
+           }
+       }
     }
 
   symbol->attr.flavor = FL_VARIABLE;
   symbol->attr.referenced = 1;
   symbol->attr.dimension = e->rank > 0;
+  symbol->attr.fe_temp = 1;
   gfc_commit_symbol (symbol);
 
   result = gfc_get_expr ();
@@ -266,8 +544,9 @@ create_var (gfc_expr * e)
       result->ref->type = REF_ARRAY;
       result->ref->u.ar.type = AR_FULL;
       result->ref->u.ar.where = e->where;
-      result->ref->u.ar.as = symbol->as;
-      if (gfc_option.warn_array_temp)
+      result->ref->u.ar.as = symbol->ts.type == BT_CLASS
+                            ? CLASS_DATA (symbol)->as : symbol->as;
+      if (warn_array_temporaries)
        gfc_warning ("Creating array temporary at %L", &(e->where));
     }
 
@@ -275,10 +554,10 @@ create_var (gfc_expr * e)
   n = XCNEW (gfc_code);
   n->op = EXEC_ASSIGN;
   n->loc = (*current_code)->loc;
-  n->next = *current_code;
+  n->next = *changed_statement;
   n->expr1 = gfc_copy_expr (result);
   n->expr2 = e;
-  *current_code = n;
+  *changed_statement = n;
 
   return result;
 }
@@ -286,7 +565,7 @@ create_var (gfc_expr * e)
 /* Warn about function elimination.  */
 
 static void
-warn_function_elimination (gfc_expr *e)
+do_warn_function_elimination (gfc_expr *e)
 {
   if (e->expr_type != EXPR_FUNCTION)
     return;
@@ -308,37 +587,46 @@ cfe_expr_0 (gfc_expr **e, int *walk_subtrees,
 {
   int i,j;
   gfc_expr *newvar;
+  gfc_expr **ei, **ej;
 
-  expr_count = 0;
+  /* Don't do this optimization within OMP workshare.  */
+
+  if (in_omp_workshare)
+    {
+      *walk_subtrees = 0;
+      return 0;
+    }
+
+  expr_array.release ();
 
   gfc_expr_walker (e, cfe_register_funcs, NULL);
 
   /* Walk through all the functions.  */
 
-  for (i=1; i<expr_count; i++)
+  FOR_EACH_VEC_ELT_FROM (expr_array, i, ei, 1)
     {
       /* Skip if the function has been replaced by a variable already.  */
-      if ((*(expr_array[i]))->expr_type == EXPR_VARIABLE)
+      if ((*ei)->expr_type == EXPR_VARIABLE)
        continue;
 
       newvar = NULL;
       for (j=0; j<i; j++)
        {
-         if (gfc_dep_compare_functions(*(expr_array[i]),
-                                       *(expr_array[j]), true) == 0)
+         ej = expr_array[j];
+         if (gfc_dep_compare_functions (*ei, *ej, true) == 0)
            {
              if (newvar == NULL)
-               newvar = create_var (*(expr_array[i]));
+               newvar = create_var (*ei);
 
-             if (gfc_option.warn_function_elimination)
-               warn_function_elimination (*(expr_array[j]));
+             if (warn_function_elimination)
+               do_warn_function_elimination (*ej);
 
-             gfc_free (*(expr_array[j]));
-             *(expr_array[j]) = gfc_copy_expr (newvar);
+             free (*ej);
+             *ej = gfc_copy_expr (newvar);
            }
        }
       if (newvar)
-       *(expr_array[i]) = newvar;
+       *ei = newvar;
     }
 
   /* We did all the necessary walking in this function.  */
@@ -351,13 +639,190 @@ cfe_expr_0 (gfc_expr **e, int *walk_subtrees,
    to insert statements as needed.  */
 
 static int
-cfe_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
-         void *data ATTRIBUTE_UNUSED)
+cfe_code (gfc_code **c, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 {
   current_code = c;
+  inserted_block = NULL;
+  changed_statement = NULL;
+
+  /* Do not do anything inside a WHERE statement; scalar assignments, BLOCKs
+     and allocation on assigment are prohibited inside WHERE, and finally
+     masking an expression would lead to wrong-code when replacing
+
+     WHERE (a>0)
+       b = sum(foo(a) + foo(a))
+     END WHERE
+
+     with
+
+     WHERE (a > 0)
+       tmp = foo(a)
+       b = sum(tmp + tmp)
+     END WHERE
+*/
+
+  if ((*c)->op == EXEC_WHERE)
+    {
+      *walk_subtrees = 0;
+      return 0;
+    }
+  
+
+  return 0;
+}
+
+/* Dummy function for expression call back, for use when we
+   really don't want to do any walking.  */
+
+static int
+dummy_expr_callback (gfc_expr **e ATTRIBUTE_UNUSED, int *walk_subtrees,
+                    void *data ATTRIBUTE_UNUSED)
+{
+  *walk_subtrees = 0;
+  return 0;
+}
+
+/* Dummy function for code callback, for use when we really
+   don't want to do anything.  */
+int
+gfc_dummy_code_callback (gfc_code **e ATTRIBUTE_UNUSED,
+                        int *walk_subtrees ATTRIBUTE_UNUSED,
+                        void *data ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+/* Code callback function for converting
+   do while(a)
+   end do
+   into the equivalent
+   do
+     if (.not. a) exit
+   end do
+   This is because common function elimination would otherwise place the
+   temporary variables outside the loop.  */
+
+static int
+convert_do_while (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
+                 void *data ATTRIBUTE_UNUSED)
+{
+  gfc_code *co = *c;
+  gfc_code *c_if1, *c_if2, *c_exit;
+  gfc_code *loopblock;
+  gfc_expr *e_not, *e_cond;
+
+  if (co->op != EXEC_DO_WHILE)
+    return 0;
+
+  if (co->expr1 == NULL || co->expr1->expr_type == EXPR_CONSTANT)
+    return 0;
+
+  e_cond = co->expr1;
+
+  /* Generate the condition of the if statement, which is .not. the original
+     statement.  */
+  e_not = gfc_get_expr ();
+  e_not->ts = e_cond->ts;
+  e_not->where = e_cond->where;
+  e_not->expr_type = EXPR_OP;
+  e_not->value.op.op = INTRINSIC_NOT;
+  e_not->value.op.op1 = e_cond;
+
+  /* Generate the EXIT statement.  */
+  c_exit = XCNEW (gfc_code);
+  c_exit->op = EXEC_EXIT;
+  c_exit->ext.which_construct = co;
+  c_exit->loc = co->loc;
+
+  /* Generate the IF statement.  */
+  c_if2 = XCNEW (gfc_code);
+  c_if2->op = EXEC_IF;
+  c_if2->expr1 = e_not;
+  c_if2->next = c_exit;
+  c_if2->loc = co->loc;
+
+  /* ... plus the one to chain it to.  */
+  c_if1 = XCNEW (gfc_code);
+  c_if1->op = EXEC_IF;
+  c_if1->block = c_if2;
+  c_if1->loc = co->loc;
+
+  /* Make the DO WHILE loop into a DO block by replacing the condition
+     with a true constant.  */
+  co->expr1 = gfc_get_logical_expr (gfc_default_integer_kind, &co->loc, true);
+
+  /* Hang the generated if statement into the loop body.  */
+
+  loopblock = co->block->next;
+  co->block->next = c_if1;
+  c_if1->next = loopblock;
+
   return 0;
 }
 
+/* Code callback function for converting
+   if (a) then
+   ...
+   else if (b) then
+   end if
+
+   into
+   if (a) then
+   else
+     if (b) then
+     end if
+   end if
+
+   because otherwise common function elimination would place the BLOCKs
+   into the wrong place.  */
+
+static int
+convert_elseif (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
+               void *data ATTRIBUTE_UNUSED)
+{
+  gfc_code *co = *c;
+  gfc_code *c_if1, *c_if2, *else_stmt;
+
+  if (co->op != EXEC_IF)
+    return 0;
+
+  /* This loop starts out with the first ELSE statement.  */
+  else_stmt = co->block->block;
+
+  while (else_stmt != NULL)
+    {
+      gfc_code *next_else;
+
+      /* If there is no condition, we're done.  */
+      if (else_stmt->expr1 == NULL)
+       break;
+
+      next_else = else_stmt->block;
+
+      /* Generate the new IF statement.  */
+      c_if2 = XCNEW (gfc_code);
+      c_if2->op = EXEC_IF;
+      c_if2->expr1 = else_stmt->expr1;
+      c_if2->next = else_stmt->next;
+      c_if2->loc = else_stmt->loc;
+      c_if2->block = next_else;
+
+      /* ... plus the one to chain it to.  */
+      c_if1 = XCNEW (gfc_code);
+      c_if1->op = EXEC_IF;
+      c_if1->block = c_if2;
+      c_if1->loc = else_stmt->loc;
+
+      /* Insert the new IF after the ELSE.  */
+      else_stmt->expr1 = NULL;
+      else_stmt->next = c_if1;
+      else_stmt->block = NULL;
+
+      else_stmt = next_else;
+    }
+  /*  Don't walk subtrees.  */
+  return 0;
+}
 /* Optimize a namespace, including all contained namespaces.  */
 
 static void
@@ -365,12 +830,37 @@ optimize_namespace (gfc_namespace *ns)
 {
 
   current_ns = ns;
+  forall_level = 0;
+  iterator_level = 0;
+  in_assoc_list = false;
+  in_omp_workshare = false;
 
+  gfc_code_walker (&ns->code, convert_do_while, dummy_expr_callback, NULL);
+  gfc_code_walker (&ns->code, convert_elseif, dummy_expr_callback, NULL);
   gfc_code_walker (&ns->code, cfe_code, cfe_expr_0, NULL);
   gfc_code_walker (&ns->code, optimize_code, optimize_expr, NULL);
 
+  /* BLOCKs are handled in the expression walker below.  */
   for (ns = ns->contained; ns; ns = ns->sibling)
-    optimize_namespace (ns);
+    {
+      if (ns->code == NULL || ns->code->op != EXEC_BLOCK)
+       optimize_namespace (ns);
+    }
+}
+
+static void
+optimize_reduction (gfc_namespace *ns)
+{
+  current_ns = ns;
+  gfc_code_walker (&ns->code, gfc_dummy_code_callback,
+                  callback_reduction, NULL);
+
+/* BLOCKs are handled in the expression walker below.  */
+  for (ns = ns->contained; ns; ns = ns->sibling)
+    {
+      if (ns->code == NULL || ns->code->op != EXEC_BLOCK)
+       optimize_reduction (ns);
+    }
 }
 
 /* Replace code like
@@ -402,6 +892,10 @@ optimize_binop_array_assignment (gfc_code *c, gfc_expr **rhs, bool seen_op)
            return true;
          break;
 
+       case INTRINSIC_CONCAT:
+         /* Do not do string concatenations.  */
+         break;
+
        default:
          /* Binary operators.  */
          if (optimize_binop_array_assignment (c, &e->value.op.op1, true))
@@ -422,7 +916,8 @@ optimize_binop_array_assignment (gfc_code *c, gfc_expr **rhs, bool seen_op)
           && ! (e->value.function.isym
                 && (e->value.function.isym->elemental
                     || e->ts.type != c->expr1->ts.type
-                    || e->ts.kind != c->expr1->ts.kind)))
+                    || e->ts.kind != c->expr1->ts.kind))
+          && ! gfc_inline_intrinsic_function_p (e))
     {
 
       gfc_code *n;
@@ -449,6 +944,35 @@ optimize_binop_array_assignment (gfc_code *c, gfc_expr **rhs, bool seen_op)
   return false;
 }
 
+/* Remove unneeded TRIMs at the end of expressions.  */
+
+static bool
+remove_trim (gfc_expr *rhs)
+{
+  bool ret;
+
+  ret = false;
+
+  /* Check for a // b // trim(c).  Looping is probably not
+     necessary because the parser usually generates
+     (// (// a b ) trim(c) ) , but better safe than sorry.  */
+
+  while (rhs->expr_type == EXPR_OP
+        && rhs->value.op.op == INTRINSIC_CONCAT)
+    rhs = rhs->value.op.op2;
+
+  while (rhs->expr_type == EXPR_FUNCTION && rhs->value.function.isym
+        && rhs->value.function.isym->id == GFC_ISYM_TRIM)
+    {
+      strip_function_call (rhs);
+      /* Recursive call to catch silly stuff like trim ( a // trim(b)).  */
+      remove_trim (rhs);
+      ret = true;
+    }
+
+  return ret;
+}
+
 /* Optimizations for an assignment.  */
 
 static void
@@ -459,18 +983,14 @@ optimize_assignment (gfc_code * c)
   lhs = c->expr1;
   rhs = c->expr2;
 
-  /* Optimize away a = trim(b), where a is a character variable.  */
-
-  if (lhs->ts.type == BT_CHARACTER)
+  if (lhs->ts.type == BT_CHARACTER && !lhs->ts.deferred)
     {
-      if (rhs->expr_type == EXPR_FUNCTION &&
-         rhs->value.function.isym &&
-         rhs->value.function.isym->id == GFC_ISYM_TRIM)
-       {
-         strip_function_call (rhs);
-         optimize_assignment (c);
-         return;
-       }
+      /* Optimize  a = trim(b)  to  a = b.  */
+      remove_trim (rhs);
+
+      /* Replace a = '   ' by a = '' to optimize away a memcpy.  */
+      if (is_empty_string (rhs))
+       rhs->value.character.length = 0;
     }
 
   if (lhs->rank > 0 && gfc_check_dependency (lhs, rhs, true) == 0)
@@ -501,7 +1021,7 @@ strip_function_call (gfc_expr *e)
 
   /* Graft the argument expression onto the original function.  */
   *e = *e1;
-  gfc_free (e1);
+  free (e1);
 
 }
 
@@ -533,28 +1053,228 @@ optimize_lexical_comparison (gfc_expr *e)
   return false;
 }
 
+/* Combine stuff like [a]>b into [a>b], for easier optimization later.  Do not
+   do CHARACTER because of possible pessimization involving character
+   lengths.  */
+
+static bool
+combine_array_constructor (gfc_expr *e)
+{
+
+  gfc_expr *op1, *op2;
+  gfc_expr *scalar;
+  gfc_expr *new_expr;
+  gfc_constructor *c, *new_c;
+  gfc_constructor_base oldbase, newbase;
+  bool scalar_first;
+
+  /* Array constructors have rank one.  */
+  if (e->rank != 1)
+    return false;
+
+  /* Don't try to combine association lists, this makes no sense
+     and leads to an ICE.  */
+  if (in_assoc_list)
+    return false;
+
+  op1 = e->value.op.op1;
+  op2 = e->value.op.op2;
+
+  if (op1->expr_type == EXPR_ARRAY && op2->rank == 0)
+    scalar_first = false;
+  else if (op2->expr_type == EXPR_ARRAY && op1->rank == 0)
+    {
+      scalar_first = true;
+      op1 = e->value.op.op2;
+      op2 = e->value.op.op1;
+    }
+  else
+    return false;
+
+  if (op2->ts.type == BT_CHARACTER)
+    return false;
+
+  scalar = create_var (gfc_copy_expr (op2));
+
+  oldbase = op1->value.constructor;
+  newbase = NULL;
+  e->expr_type = EXPR_ARRAY;
+
+  for (c = gfc_constructor_first (oldbase); c;
+       c = gfc_constructor_next (c))
+    {
+      new_expr = gfc_get_expr ();
+      new_expr->ts = e->ts;
+      new_expr->expr_type = EXPR_OP;
+      new_expr->rank = c->expr->rank;
+      new_expr->where = c->where;
+      new_expr->value.op.op = e->value.op.op;
+
+      if (scalar_first)
+       {
+         new_expr->value.op.op1 = gfc_copy_expr (scalar);
+         new_expr->value.op.op2 = gfc_copy_expr (c->expr);
+       }
+      else
+       {
+         new_expr->value.op.op1 = gfc_copy_expr (c->expr);
+         new_expr->value.op.op2 = gfc_copy_expr (scalar);
+       }
+
+      new_c = gfc_constructor_append_expr (&newbase, new_expr, &(e->where));
+      new_c->iterator = c->iterator;
+      c->iterator = NULL;
+    }
+
+  gfc_free_expr (op1);
+  gfc_free_expr (op2);
+  gfc_free_expr (scalar);
+
+  e->value.constructor = newbase;
+  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
 optimize_op (gfc_expr *e)
 {
+  bool changed;
+
   gfc_intrinsic_op op = e->value.op.op;
 
+  changed = false;
+
+  /* Only use new-style comparisons.  */
+  switch(op)
+    {
+    case INTRINSIC_EQ_OS:
+      op = INTRINSIC_EQ;
+      break;
+
+    case INTRINSIC_GE_OS:
+      op = INTRINSIC_GE;
+      break;
+
+    case INTRINSIC_LE_OS:
+      op = INTRINSIC_LE;
+      break;
+
+    case INTRINSIC_NE_OS:
+      op = INTRINSIC_NE;
+      break;
+
+    case INTRINSIC_GT_OS:
+      op = INTRINSIC_GT;
+      break;
+
+    case INTRINSIC_LT_OS:
+      op = INTRINSIC_LT;
+      break;
+
+    default:
+      break;
+    }
+
   switch (op)
     {
     case INTRINSIC_EQ:
-    case INTRINSIC_EQ_OS:
     case INTRINSIC_GE:
-    case INTRINSIC_GE_OS:
     case INTRINSIC_LE:
-    case INTRINSIC_LE_OS:
     case INTRINSIC_NE:
-    case INTRINSIC_NE_OS:
     case INTRINSIC_GT:
-    case INTRINSIC_GT_OS:
     case INTRINSIC_LT:
-    case INTRINSIC_LT_OS:
-      return optimize_comparison (e, op);
+      changed = optimize_comparison (e, op);
+
+      /* Fall through */
+      /* Look at array constructors.  */
+    case INTRINSIC_PLUS:
+    case INTRINSIC_MINUS:
+    case INTRINSIC_TIMES:
+    case INTRINSIC_DIVIDE:
+      return combine_array_constructor (e) || changed;
+
+    case INTRINSIC_POWER:
+      return optimize_power (e);
+      break;
 
     default:
       break;
@@ -563,6 +1283,63 @@ optimize_op (gfc_expr *e)
   return false;
 }
 
+
+/* Return true if a constant string contains only blanks.  */
+
+static bool
+is_empty_string (gfc_expr *e)
+{
+  int i;
+
+  if (e->ts.type != BT_CHARACTER || e->expr_type != EXPR_CONSTANT)
+    return false;
+
+  for (i=0; i < e->value.character.length; i++)
+    {
+      if (e->value.character.string[i] != ' ')
+       return false;
+    }
+
+  return true;
+}
+
+
+/* Insert a call to the intrinsic len_trim. Use a different name for
+   the symbol tree so we don't run into trouble when the user has
+   renamed len_trim for some reason.  */
+
+static gfc_expr*
+get_len_trim_call (gfc_expr *str, int kind)
+{
+  gfc_expr *fcn;
+  gfc_actual_arglist *actual_arglist, *next;
+
+  fcn = gfc_get_expr ();
+  fcn->expr_type = EXPR_FUNCTION;
+  fcn->value.function.isym = gfc_intrinsic_function_by_id (GFC_ISYM_LEN_TRIM);
+  actual_arglist = gfc_get_actual_arglist ();
+  actual_arglist->expr = str;
+  next = gfc_get_actual_arglist ();
+  next->expr = gfc_get_int_expr (gfc_default_integer_kind, NULL, kind);
+  actual_arglist->next = next;
+
+  fcn->value.function.actual = actual_arglist;
+  fcn->where = str->where;
+  fcn->ts.type = BT_INTEGER;
+  fcn->ts.kind = gfc_charlen_int_kind;
+
+  gfc_get_sym_tree ("__internal_len_trim", current_ns, &fcn->symtree, false);
+  fcn->symtree->n.sym->ts = fcn->ts;
+  fcn->symtree->n.sym->attr.flavor = FL_PROCEDURE;
+  fcn->symtree->n.sym->attr.function = 1;
+  fcn->symtree->n.sym->attr.elemental = 1;
+  fcn->symtree->n.sym->attr.referenced = 1;
+  fcn->symtree->n.sym->attr.access = ACCESS_PRIVATE;
+  gfc_commit_symbol (fcn->symtree->n.sym);
+
+  return fcn;
+}
+
 /* Optimize expressions for equality.  */
 
 static bool
@@ -583,7 +1360,7 @@ optimize_comparison (gfc_expr *e, gfc_intrinsic_op op)
     }
   else if (e->expr_type == EXPR_FUNCTION)
     {
-      /* One of the lexical comparision functions.  */
+      /* One of the lexical comparison functions.  */
       firstarg = e->value.function.actual;
       secondarg = firstarg->next;
       op1 = firstarg->expr;
@@ -594,36 +1371,56 @@ optimize_comparison (gfc_expr *e, gfc_intrinsic_op op)
 
   /* Strip off unneeded TRIM calls from string comparisons.  */
 
-  change = false;
+  change = remove_trim (op1);
 
-  if (op1->expr_type == EXPR_FUNCTION 
-      && op1->value.function.isym
-      && op1->value.function.isym->id == GFC_ISYM_TRIM)
-    {
-      strip_function_call (op1);
-      change = true;
-    }
-
-  if (op2->expr_type == EXPR_FUNCTION 
-      && op2->value.function.isym
-      && op2->value.function.isym->id == GFC_ISYM_TRIM)
-    {
-      strip_function_call (op2);
-      change = true;
-    }
-
-  if (change)
-    {
-      optimize_comparison (e, op);
-      return true;
-    }
+  if (remove_trim (op2))
+    change = true;
 
   /* An expression of type EXPR_CONSTANT is only valid for scalars.  */
   /* TODO: A scalar constant may be acceptable in some cases (the scalarizer
      handles them well). However, there are also cases that need a non-scalar
      argument. For example the any intrinsic. See PR 45380.  */
   if (e->rank > 0)
-    return false;
+    return change;
+
+  /* Replace a == '' with len_trim(a) == 0 and a /= '' with
+     len_trim(a) != 0 */
+  if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER
+      && (op == INTRINSIC_EQ || op == INTRINSIC_NE))
+    {
+      bool empty_op1, empty_op2;
+      empty_op1 = is_empty_string (op1);
+      empty_op2 = is_empty_string (op2);
+
+      if (empty_op1 || empty_op2)
+       {
+         gfc_expr *fcn;
+         gfc_expr *zero;
+         gfc_expr *str;
+
+         /* This can only happen when an error for comparing
+            characters of different kinds has already been issued.  */
+         if (empty_op1 && empty_op2)
+           return false;
+
+         zero = gfc_get_int_expr (gfc_charlen_int_kind, &e->where, 0);
+         str = empty_op1 ? op2 : op1;
+
+         fcn = get_len_trim_call (str, gfc_charlen_int_kind);
+
+
+         if (empty_op1)
+           gfc_free_expr (op1);
+         else
+           gfc_free_expr (op2);
+
+         op1 = fcn;
+         op2 = zero;
+         e->value.op.op1 = fcn;
+         e->value.op.op2 = zero;
+       }
+    }
+
 
   /* Don't compare REAL or COMPLEX expressions when honoring NaNs.  */
 
@@ -632,12 +1429,14 @@ optimize_comparison (gfc_expr *e, gfc_intrinsic_op op)
          && op1->ts.type != BT_COMPLEX && op2->ts.type != BT_COMPLEX))
     {
       eq = gfc_dep_compare_expr (op1, op2);
-      if (eq == -2)
+      if (eq <= -2)
        {
          /* Replace A // B < A // C with B < C, and A // B < C // B
             with A < C.  */
          if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER
+             && op1->expr_type == EXPR_OP
              && op1->value.op.op == INTRINSIC_CONCAT
+             && op2->expr_type == EXPR_OP
              && op2->value.op.op == INTRINSIC_CONCAT)
            {
              gfc_expr *op1_left = op1->value.op.op1;
@@ -653,11 +1452,11 @@ optimize_comparison (gfc_expr *e, gfc_intrinsic_op op)
                        && op2_left->expr_type == EXPR_CONSTANT
                        && op1_left->value.character.length
                           != op2_left->value.character.length)
-                   return false;
+                   return change;
                  else
                    {
-                     gfc_free (op1_left);
-                     gfc_free (op2_left);
+                     free (op1_left);
+                     free (op2_left);
                      if (firstarg)
                        {
                          firstarg->expr = op1_right;
@@ -674,8 +1473,8 @@ optimize_comparison (gfc_expr *e, gfc_intrinsic_op op)
                }
              if (gfc_dep_compare_expr (op1_right, op2_right) == 0)
                {
-                 gfc_free (op1_right);
-                 gfc_free (op2_right);
+                 free (op1_right);
+                 free (op2_right);
                  if (firstarg)
                    {
                      firstarg->expr = op1_left;
@@ -698,32 +1497,26 @@ optimize_comparison (gfc_expr *e, gfc_intrinsic_op op)
          switch (op)
            {
            case INTRINSIC_EQ:
-           case INTRINSIC_EQ_OS:
              result = eq == 0;
              break;
              
            case INTRINSIC_GE:
-           case INTRINSIC_GE_OS:
              result = eq >= 0;
              break;
 
            case INTRINSIC_LE:
-           case INTRINSIC_LE_OS:
              result = eq <= 0;
              break;
 
            case INTRINSIC_NE:
-           case INTRINSIC_NE_OS:
              result = eq != 0;
              break;
 
            case INTRINSIC_GT:
-           case INTRINSIC_GT_OS:
              result = eq > 0;
              break;
 
            case INTRINSIC_LT:
-           case INTRINSIC_LT_OS:
              result = eq < 0;
              break;
              
@@ -734,15 +1527,15 @@ optimize_comparison (gfc_expr *e, gfc_intrinsic_op op)
 
          /* Replace the expression by a constant expression.  The typespec
             and where remains the way it is.  */
-         gfc_free (op1);
-         gfc_free (op2);
+         free (op1);
+         free (op2);
          e->expr_type = EXPR_CONSTANT;
          e->value.logical = result;
          return true;
        }
     }
 
-  return false;
+  return change;
 }
 
 /* Optimize a trim function by replacing it with an equivalent substring
@@ -755,7 +1548,6 @@ optimize_trim (gfc_expr *e)
   gfc_expr *a;
   gfc_ref *ref;
   gfc_expr *fcn;
-  gfc_actual_arglist *actual_arglist, *next;
   gfc_ref **rr = NULL;
 
   /* Don't do this optimization within an argument list, because
@@ -802,28 +1594,219 @@ optimize_trim (gfc_expr *e)
 
   ref->u.ss.start = gfc_get_int_expr (gfc_default_integer_kind, NULL, 1);
 
-  /* Build the function call to len_trim(x, gfc_defaul_integer_kind).  */
+  /* Build the function call to len_trim(x, gfc_default_integer_kind).  */
 
-  fcn = gfc_get_expr ();
-  fcn->expr_type = EXPR_FUNCTION;
-  fcn->value.function.isym =
-    gfc_intrinsic_function_by_id (GFC_ISYM_LEN_TRIM);
-  actual_arglist = gfc_get_actual_arglist ();
-  actual_arglist->expr = gfc_copy_expr (e);
-  next = gfc_get_actual_arglist ();
-  next->expr = gfc_get_int_expr (gfc_default_integer_kind, NULL,
-                                gfc_default_integer_kind);
-  actual_arglist->next = next;
-  fcn->value.function.actual = actual_arglist;
+  fcn = get_len_trim_call (gfc_copy_expr (e), gfc_default_integer_kind);
 
   /* Set the end of the reference to the call to len_trim.  */
 
   ref->u.ss.end = fcn;
-  gcc_assert (*rr == NULL);
+  gcc_assert (rr != NULL && *rr == NULL);
   *rr = ref;
   return true;
 }
 
+/* Optimize minloc(b), where b is rank 1 array, into
+   (/ minloc(b, dim=1) /), and similarly for maxloc,
+   as the latter forms are expanded inline.  */
+
+static void
+optimize_minmaxloc (gfc_expr **e)
+{
+  gfc_expr *fn = *e;
+  gfc_actual_arglist *a;
+  char *name, *p;
+
+  if (fn->rank != 1
+      || fn->value.function.actual == NULL
+      || fn->value.function.actual->expr == NULL
+      || fn->value.function.actual->expr->rank != 1)
+    return;
+
+  *e = gfc_get_array_expr (fn->ts.type, fn->ts.kind, &fn->where);
+  (*e)->shape = fn->shape;
+  fn->rank = 0;
+  fn->shape = NULL;
+  gfc_constructor_append_expr (&(*e)->value.constructor, fn, &fn->where);
+
+  name = XALLOCAVEC (char, strlen (fn->value.function.name) + 1);
+  strcpy (name, fn->value.function.name);
+  p = strstr (name, "loc0");
+  p[3] = '1';
+  fn->value.function.name = gfc_get_string (name);
+  if (fn->value.function.actual->next)
+    {
+      a = fn->value.function.actual->next;
+      gcc_assert (a->expr == NULL);
+    }
+  else
+    {
+      a = gfc_get_actual_arglist ();
+      fn->value.function.actual->next = a;
+    }
+  a->expr = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind,
+                                  &fn->where);
+  mpz_set_ui (a->expr->value.integer, 1);
+}
+
+/* Callback function for code checking that we do not pass a DO variable to an
+   INTENT(OUT) or INTENT(INOUT) dummy variable.  */
+
+static int
+doloop_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
+        void *data ATTRIBUTE_UNUSED)
+{
+  gfc_code *co;
+  int i;
+  gfc_formal_arglist *f;
+  gfc_actual_arglist *a;
+  gfc_code *cl;
+
+  co = *c;
+
+  /* If the doloop_list grew, we have to truncate it here.  */
+
+  if ((unsigned) doloop_level < doloop_list.length())
+    doloop_list.truncate (doloop_level);
+
+  switch (co->op)
+    {
+    case EXEC_DO:
+
+      if (co->ext.iterator && co->ext.iterator->var)
+       doloop_list.safe_push (co);
+      else
+       doloop_list.safe_push ((gfc_code *) NULL);
+      break;
+
+    case EXEC_CALL:
+
+      if (co->resolved_sym == NULL)
+       break;
+
+      f = gfc_sym_get_dummy_args (co->resolved_sym);
+
+      /* Withot a formal arglist, there is only unknown INTENT,
+        which we don't check for.  */
+      if (f == NULL)
+       break;
+
+      a = co->ext.actual;
+
+      while (a && f)
+       {
+         FOR_EACH_VEC_ELT (doloop_list, i, cl)
+           {
+             gfc_symbol *do_sym;
+             
+             if (cl == NULL)
+               break;
+
+             do_sym = cl->ext.iterator->var->symtree->n.sym;
+             
+             if (a->expr && a->expr->symtree
+                 && a->expr->symtree->n.sym == do_sym)
+               {
+                 if (f->sym->attr.intent == INTENT_OUT)
+                   gfc_error_now_1 ("Variable '%s' at %L set to undefined "
+                                    "value inside loop  beginning at %L as "
+                                    "INTENT(OUT) argument to subroutine '%s'",
+                                    do_sym->name, &a->expr->where,
+                                    &doloop_list[i]->loc,
+                                    co->symtree->n.sym->name);
+                 else if (f->sym->attr.intent == INTENT_INOUT)
+                   gfc_error_now_1 ("Variable '%s' at %L not definable inside "
+                                    "loop beginning at %L as INTENT(INOUT) "
+                                    "argument to subroutine '%s'",
+                                    do_sym->name, &a->expr->where,
+                                    &doloop_list[i]->loc,
+                                    co->symtree->n.sym->name);
+               }
+           }
+         a = a->next;
+         f = f->next;
+       }
+      break;
+
+    default:
+      break;
+    }
+  return 0;
+}
+
+/* Callback function for functions checking that we do not pass a DO variable
+   to an INTENT(OUT) or INTENT(INOUT) dummy variable.  */
+
+static int
+do_function (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
+            void *data ATTRIBUTE_UNUSED)
+{
+  gfc_formal_arglist *f;
+  gfc_actual_arglist *a;
+  gfc_expr *expr;
+  gfc_code *dl;
+  int i;
+
+  expr = *e;
+  if (expr->expr_type != EXPR_FUNCTION)
+    return 0;
+
+  /* Intrinsic functions don't modify their arguments.  */
+
+  if (expr->value.function.isym)
+    return 0;
+
+  f = gfc_sym_get_dummy_args (expr->symtree->n.sym);
+
+  /* Without a formal arglist, there is only unknown INTENT,
+     which we don't check for.  */
+  if (f == NULL)
+    return 0;
+
+  a = expr->value.function.actual;
+
+  while (a && f)
+    {
+      FOR_EACH_VEC_ELT (doloop_list, i, dl)
+       {
+         gfc_symbol *do_sym;
+
+         if (dl == NULL)
+           break;
+
+         do_sym = dl->ext.iterator->var->symtree->n.sym;
+         
+         if (a->expr && a->expr->symtree
+             && a->expr->symtree->n.sym == do_sym)
+           {
+             if (f->sym->attr.intent == INTENT_OUT)
+               gfc_error_now_1 ("Variable '%s' at %L set to undefined value "
+                                "inside loop beginning at %L as INTENT(OUT) "
+                                "argument to function '%s'", do_sym->name,
+                                &a->expr->where, &doloop_list[i]->loc,
+                                expr->symtree->n.sym->name);
+             else if (f->sym->attr.intent == INTENT_INOUT)
+               gfc_error_now_1 ("Variable '%s' at %L not definable inside loop"
+                                " beginning at %L as INTENT(INOUT) argument to"
+                                " function '%s'", do_sym->name,
+                                &a->expr->where, &doloop_list[i]->loc,
+                                expr->symtree->n.sym->name);
+           }
+       }
+      a = a->next;
+      f = f->next;
+    }
+
+  return 0;
+}
+
+static void
+doloop_warn (gfc_namespace *ns)
+{
+  gfc_code_walker (&ns->code, doloop_code, do_function, NULL);
+}
+
+
 #define WALK_SUBEXPR(NODE) \
   do                                                   \
     {                                                  \
@@ -872,9 +1855,13 @@ gfc_expr_walker (gfc_expr **e, walk_expr_fn_t exprfn, void *data)
            for (c = gfc_constructor_first ((*e)->value.constructor); c;
                 c = gfc_constructor_next (c))
              {
-               WALK_SUBEXPR (c->expr);
-               if (c->iterator != NULL)
+               if (c->iterator == NULL)
+                 WALK_SUBEXPR (c->expr);
+               else
                  {
+                   iterator_level ++;
+                   WALK_SUBEXPR (c->expr);
+                   iterator_level --;
                    WALK_SUBEXPR (c->iterator->var);
                    WALK_SUBEXPR (c->iterator->start);
                    WALK_SUBEXPR (c->iterator->end);
@@ -958,31 +1945,57 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
        {
          gfc_code *b;
          gfc_actual_arglist *a;
+         gfc_code *co;
+         gfc_association_list *alist;
+         bool saved_in_omp_workshare;
+
+         /* There might be statement insertions before the current code,
+            which must not affect the expression walker.  */
 
-         switch ((*c)->op)
+         co = *c;
+         saved_in_omp_workshare = in_omp_workshare;
+
+         switch (co->op)
            {
+
+           case EXEC_BLOCK:
+             WALK_SUBCODE (co->ext.block.ns->code);
+             if (co->ext.block.assoc)
+               {
+                 bool saved_in_assoc_list = in_assoc_list;
+
+                 in_assoc_list = true;
+                 for (alist = co->ext.block.assoc; alist; alist = alist->next)
+                   WALK_SUBEXPR (alist->target);
+
+                 in_assoc_list = saved_in_assoc_list;
+               }
+
+             break;
+
            case EXEC_DO:
-             WALK_SUBEXPR ((*c)->ext.iterator->var);
-             WALK_SUBEXPR ((*c)->ext.iterator->start);
-             WALK_SUBEXPR ((*c)->ext.iterator->end);
-             WALK_SUBEXPR ((*c)->ext.iterator->step);
+             doloop_level ++;
+             WALK_SUBEXPR (co->ext.iterator->var);
+             WALK_SUBEXPR (co->ext.iterator->start);
+             WALK_SUBEXPR (co->ext.iterator->end);
+             WALK_SUBEXPR (co->ext.iterator->step);
              break;
 
            case EXEC_CALL:
            case EXEC_ASSIGN_CALL:
-             for (a = (*c)->ext.actual; a; a = a->next)
+             for (a = co->ext.actual; a; a = a->next)
                WALK_SUBEXPR (a->expr);
              break;
 
            case EXEC_CALL_PPC:
-             WALK_SUBEXPR ((*c)->expr1);
-             for (a = (*c)->ext.actual; a; a = a->next)
+             WALK_SUBEXPR (co->expr1);
+             for (a = co->ext.actual; a; a = a->next)
                WALK_SUBEXPR (a->expr);
              break;
 
            case EXEC_SELECT:
-             WALK_SUBEXPR ((*c)->expr1);
-             for (b = (*c)->block; b; b = b->block)
+             WALK_SUBEXPR (co->expr1);
+             for (b = co->block; b; b = b->block)
                {
                  gfc_case *cp;
                  for (cp = b->ext.block.case_list; cp; cp = cp->next)
@@ -998,161 +2011,229 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
            case EXEC_DEALLOCATE:
              {
                gfc_alloc *a;
-               for (a = (*c)->ext.alloc.list; a; a = a->next)
+               for (a = co->ext.alloc.list; a; a = a->next)
                  WALK_SUBEXPR (a->expr);
                break;
              }
 
            case EXEC_FORALL:
+           case EXEC_DO_CONCURRENT:
              {
                gfc_forall_iterator *fa;
-               for (fa = (*c)->ext.forall_iterator; fa; fa = fa->next)
+               for (fa = co->ext.forall_iterator; fa; fa = fa->next)
                  {
                    WALK_SUBEXPR (fa->var);
                    WALK_SUBEXPR (fa->start);
                    WALK_SUBEXPR (fa->end);
                    WALK_SUBEXPR (fa->stride);
                  }
+               if (co->op == EXEC_FORALL)
+                 forall_level ++;
                break;
              }
 
            case EXEC_OPEN:
-             WALK_SUBEXPR ((*c)->ext.open->unit);
-             WALK_SUBEXPR ((*c)->ext.open->file);
-             WALK_SUBEXPR ((*c)->ext.open->status);
-             WALK_SUBEXPR ((*c)->ext.open->access);
-             WALK_SUBEXPR ((*c)->ext.open->form);
-             WALK_SUBEXPR ((*c)->ext.open->recl);
-             WALK_SUBEXPR ((*c)->ext.open->blank);
-             WALK_SUBEXPR ((*c)->ext.open->position);
-             WALK_SUBEXPR ((*c)->ext.open->action);
-             WALK_SUBEXPR ((*c)->ext.open->delim);
-             WALK_SUBEXPR ((*c)->ext.open->pad);
-             WALK_SUBEXPR ((*c)->ext.open->iostat);
-             WALK_SUBEXPR ((*c)->ext.open->iomsg);
-             WALK_SUBEXPR ((*c)->ext.open->convert);
-             WALK_SUBEXPR ((*c)->ext.open->decimal);
-             WALK_SUBEXPR ((*c)->ext.open->encoding);
-             WALK_SUBEXPR ((*c)->ext.open->round);
-             WALK_SUBEXPR ((*c)->ext.open->sign);
-             WALK_SUBEXPR ((*c)->ext.open->asynchronous);
-             WALK_SUBEXPR ((*c)->ext.open->id);
-             WALK_SUBEXPR ((*c)->ext.open->newunit);
+             WALK_SUBEXPR (co->ext.open->unit);
+             WALK_SUBEXPR (co->ext.open->file);
+             WALK_SUBEXPR (co->ext.open->status);
+             WALK_SUBEXPR (co->ext.open->access);
+             WALK_SUBEXPR (co->ext.open->form);
+             WALK_SUBEXPR (co->ext.open->recl);
+             WALK_SUBEXPR (co->ext.open->blank);
+             WALK_SUBEXPR (co->ext.open->position);
+             WALK_SUBEXPR (co->ext.open->action);
+             WALK_SUBEXPR (co->ext.open->delim);
+             WALK_SUBEXPR (co->ext.open->pad);
+             WALK_SUBEXPR (co->ext.open->iostat);
+             WALK_SUBEXPR (co->ext.open->iomsg);
+             WALK_SUBEXPR (co->ext.open->convert);
+             WALK_SUBEXPR (co->ext.open->decimal);
+             WALK_SUBEXPR (co->ext.open->encoding);
+             WALK_SUBEXPR (co->ext.open->round);
+             WALK_SUBEXPR (co->ext.open->sign);
+             WALK_SUBEXPR (co->ext.open->asynchronous);
+             WALK_SUBEXPR (co->ext.open->id);
+             WALK_SUBEXPR (co->ext.open->newunit);
              break;
 
            case EXEC_CLOSE:
-             WALK_SUBEXPR ((*c)->ext.close->unit);
-             WALK_SUBEXPR ((*c)->ext.close->status);
-             WALK_SUBEXPR ((*c)->ext.close->iostat);
-             WALK_SUBEXPR ((*c)->ext.close->iomsg);
+             WALK_SUBEXPR (co->ext.close->unit);
+             WALK_SUBEXPR (co->ext.close->status);
+             WALK_SUBEXPR (co->ext.close->iostat);
+             WALK_SUBEXPR (co->ext.close->iomsg);
              break;
 
            case EXEC_BACKSPACE:
            case EXEC_ENDFILE:
            case EXEC_REWIND:
            case EXEC_FLUSH:
-             WALK_SUBEXPR ((*c)->ext.filepos->unit);
-             WALK_SUBEXPR ((*c)->ext.filepos->iostat);
-             WALK_SUBEXPR ((*c)->ext.filepos->iomsg);
+             WALK_SUBEXPR (co->ext.filepos->unit);
+             WALK_SUBEXPR (co->ext.filepos->iostat);
+             WALK_SUBEXPR (co->ext.filepos->iomsg);
              break;
 
            case EXEC_INQUIRE:
-             WALK_SUBEXPR ((*c)->ext.inquire->unit);
-             WALK_SUBEXPR ((*c)->ext.inquire->file);
-             WALK_SUBEXPR ((*c)->ext.inquire->iomsg);
-             WALK_SUBEXPR ((*c)->ext.inquire->iostat);
-             WALK_SUBEXPR ((*c)->ext.inquire->exist);
-             WALK_SUBEXPR ((*c)->ext.inquire->opened);
-             WALK_SUBEXPR ((*c)->ext.inquire->number);
-             WALK_SUBEXPR ((*c)->ext.inquire->named);
-             WALK_SUBEXPR ((*c)->ext.inquire->name);
-             WALK_SUBEXPR ((*c)->ext.inquire->access);
-             WALK_SUBEXPR ((*c)->ext.inquire->sequential);
-             WALK_SUBEXPR ((*c)->ext.inquire->direct);
-             WALK_SUBEXPR ((*c)->ext.inquire->form);
-             WALK_SUBEXPR ((*c)->ext.inquire->formatted);
-             WALK_SUBEXPR ((*c)->ext.inquire->unformatted);
-             WALK_SUBEXPR ((*c)->ext.inquire->recl);
-             WALK_SUBEXPR ((*c)->ext.inquire->nextrec);
-             WALK_SUBEXPR ((*c)->ext.inquire->blank);
-             WALK_SUBEXPR ((*c)->ext.inquire->position);
-             WALK_SUBEXPR ((*c)->ext.inquire->action);
-             WALK_SUBEXPR ((*c)->ext.inquire->read);
-             WALK_SUBEXPR ((*c)->ext.inquire->write);
-             WALK_SUBEXPR ((*c)->ext.inquire->readwrite);
-             WALK_SUBEXPR ((*c)->ext.inquire->delim);
-             WALK_SUBEXPR ((*c)->ext.inquire->encoding);
-             WALK_SUBEXPR ((*c)->ext.inquire->pad);
-             WALK_SUBEXPR ((*c)->ext.inquire->iolength);
-             WALK_SUBEXPR ((*c)->ext.inquire->convert);
-             WALK_SUBEXPR ((*c)->ext.inquire->strm_pos);
-             WALK_SUBEXPR ((*c)->ext.inquire->asynchronous);
-             WALK_SUBEXPR ((*c)->ext.inquire->decimal);
-             WALK_SUBEXPR ((*c)->ext.inquire->pending);
-             WALK_SUBEXPR ((*c)->ext.inquire->id);
-             WALK_SUBEXPR ((*c)->ext.inquire->sign);
-             WALK_SUBEXPR ((*c)->ext.inquire->size);
-             WALK_SUBEXPR ((*c)->ext.inquire->round);
+             WALK_SUBEXPR (co->ext.inquire->unit);
+             WALK_SUBEXPR (co->ext.inquire->file);
+             WALK_SUBEXPR (co->ext.inquire->iomsg);
+             WALK_SUBEXPR (co->ext.inquire->iostat);
+             WALK_SUBEXPR (co->ext.inquire->exist);
+             WALK_SUBEXPR (co->ext.inquire->opened);
+             WALK_SUBEXPR (co->ext.inquire->number);
+             WALK_SUBEXPR (co->ext.inquire->named);
+             WALK_SUBEXPR (co->ext.inquire->name);
+             WALK_SUBEXPR (co->ext.inquire->access);
+             WALK_SUBEXPR (co->ext.inquire->sequential);
+             WALK_SUBEXPR (co->ext.inquire->direct);
+             WALK_SUBEXPR (co->ext.inquire->form);
+             WALK_SUBEXPR (co->ext.inquire->formatted);
+             WALK_SUBEXPR (co->ext.inquire->unformatted);
+             WALK_SUBEXPR (co->ext.inquire->recl);
+             WALK_SUBEXPR (co->ext.inquire->nextrec);
+             WALK_SUBEXPR (co->ext.inquire->blank);
+             WALK_SUBEXPR (co->ext.inquire->position);
+             WALK_SUBEXPR (co->ext.inquire->action);
+             WALK_SUBEXPR (co->ext.inquire->read);
+             WALK_SUBEXPR (co->ext.inquire->write);
+             WALK_SUBEXPR (co->ext.inquire->readwrite);
+             WALK_SUBEXPR (co->ext.inquire->delim);
+             WALK_SUBEXPR (co->ext.inquire->encoding);
+             WALK_SUBEXPR (co->ext.inquire->pad);
+             WALK_SUBEXPR (co->ext.inquire->iolength);
+             WALK_SUBEXPR (co->ext.inquire->convert);
+             WALK_SUBEXPR (co->ext.inquire->strm_pos);
+             WALK_SUBEXPR (co->ext.inquire->asynchronous);
+             WALK_SUBEXPR (co->ext.inquire->decimal);
+             WALK_SUBEXPR (co->ext.inquire->pending);
+             WALK_SUBEXPR (co->ext.inquire->id);
+             WALK_SUBEXPR (co->ext.inquire->sign);
+             WALK_SUBEXPR (co->ext.inquire->size);
+             WALK_SUBEXPR (co->ext.inquire->round);
              break;
 
            case EXEC_WAIT:
-             WALK_SUBEXPR ((*c)->ext.wait->unit);
-             WALK_SUBEXPR ((*c)->ext.wait->iostat);
-             WALK_SUBEXPR ((*c)->ext.wait->iomsg);
-             WALK_SUBEXPR ((*c)->ext.wait->id);
+             WALK_SUBEXPR (co->ext.wait->unit);
+             WALK_SUBEXPR (co->ext.wait->iostat);
+             WALK_SUBEXPR (co->ext.wait->iomsg);
+             WALK_SUBEXPR (co->ext.wait->id);
              break;
 
            case EXEC_READ:
            case EXEC_WRITE:
-             WALK_SUBEXPR ((*c)->ext.dt->io_unit);
-             WALK_SUBEXPR ((*c)->ext.dt->format_expr);
-             WALK_SUBEXPR ((*c)->ext.dt->rec);
-             WALK_SUBEXPR ((*c)->ext.dt->advance);
-             WALK_SUBEXPR ((*c)->ext.dt->iostat);
-             WALK_SUBEXPR ((*c)->ext.dt->size);
-             WALK_SUBEXPR ((*c)->ext.dt->iomsg);
-             WALK_SUBEXPR ((*c)->ext.dt->id);
-             WALK_SUBEXPR ((*c)->ext.dt->pos);
-             WALK_SUBEXPR ((*c)->ext.dt->asynchronous);
-             WALK_SUBEXPR ((*c)->ext.dt->blank);
-             WALK_SUBEXPR ((*c)->ext.dt->decimal);
-             WALK_SUBEXPR ((*c)->ext.dt->delim);
-             WALK_SUBEXPR ((*c)->ext.dt->pad);
-             WALK_SUBEXPR ((*c)->ext.dt->round);
-             WALK_SUBEXPR ((*c)->ext.dt->sign);
-             WALK_SUBEXPR ((*c)->ext.dt->extra_comma);
+             WALK_SUBEXPR (co->ext.dt->io_unit);
+             WALK_SUBEXPR (co->ext.dt->format_expr);
+             WALK_SUBEXPR (co->ext.dt->rec);
+             WALK_SUBEXPR (co->ext.dt->advance);
+             WALK_SUBEXPR (co->ext.dt->iostat);
+             WALK_SUBEXPR (co->ext.dt->size);
+             WALK_SUBEXPR (co->ext.dt->iomsg);
+             WALK_SUBEXPR (co->ext.dt->id);
+             WALK_SUBEXPR (co->ext.dt->pos);
+             WALK_SUBEXPR (co->ext.dt->asynchronous);
+             WALK_SUBEXPR (co->ext.dt->blank);
+             WALK_SUBEXPR (co->ext.dt->decimal);
+             WALK_SUBEXPR (co->ext.dt->delim);
+             WALK_SUBEXPR (co->ext.dt->pad);
+             WALK_SUBEXPR (co->ext.dt->round);
+             WALK_SUBEXPR (co->ext.dt->sign);
+             WALK_SUBEXPR (co->ext.dt->extra_comma);
              break;
 
-           case EXEC_OMP_DO:
            case EXEC_OMP_PARALLEL:
            case EXEC_OMP_PARALLEL_DO:
+           case EXEC_OMP_PARALLEL_DO_SIMD:
            case EXEC_OMP_PARALLEL_SECTIONS:
+
+             in_omp_workshare = false;
+
+             /* This goto serves as a shortcut to avoid code
+                duplication or a larger if or switch statement.  */
+             goto check_omp_clauses;
+             
+           case EXEC_OMP_WORKSHARE:
            case EXEC_OMP_PARALLEL_WORKSHARE:
+
+             in_omp_workshare = true;
+
+             /* Fall through  */
+
+           case EXEC_OMP_DISTRIBUTE:
+           case EXEC_OMP_DISTRIBUTE_PARALLEL_DO:
+           case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD:
+           case EXEC_OMP_DISTRIBUTE_SIMD:
+           case EXEC_OMP_DO:
+           case EXEC_OMP_DO_SIMD:
            case EXEC_OMP_SECTIONS:
            case EXEC_OMP_SINGLE:
-           case EXEC_OMP_WORKSHARE:
            case EXEC_OMP_END_SINGLE:
+           case EXEC_OMP_SIMD:
+           case EXEC_OMP_TARGET:
+           case EXEC_OMP_TARGET_DATA:
+           case EXEC_OMP_TARGET_TEAMS:
+           case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE:
+           case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO:
+           case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
+           case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD:
+           case EXEC_OMP_TARGET_UPDATE:
            case EXEC_OMP_TASK:
-             if ((*c)->ext.omp_clauses)
+           case EXEC_OMP_TEAMS:
+           case EXEC_OMP_TEAMS_DISTRIBUTE:
+           case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO:
+           case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
+           case EXEC_OMP_TEAMS_DISTRIBUTE_SIMD:
+
+             /* Come to this label only from the
+                EXEC_OMP_PARALLEL_* cases above.  */
+
+           check_omp_clauses:
+
+             if (co->ext.omp_clauses)
                {
-                 WALK_SUBEXPR ((*c)->ext.omp_clauses->if_expr);
-                 WALK_SUBEXPR ((*c)->ext.omp_clauses->num_threads);
-                 WALK_SUBEXPR ((*c)->ext.omp_clauses->chunk_size);
+                 gfc_omp_namelist *n;
+                 static int list_types[]
+                   = { OMP_LIST_ALIGNED, OMP_LIST_LINEAR, OMP_LIST_DEPEND,
+                       OMP_LIST_MAP, OMP_LIST_TO, OMP_LIST_FROM };
+                 size_t idx;
+                 WALK_SUBEXPR (co->ext.omp_clauses->if_expr);
+                 WALK_SUBEXPR (co->ext.omp_clauses->final_expr);
+                 WALK_SUBEXPR (co->ext.omp_clauses->num_threads);
+                 WALK_SUBEXPR (co->ext.omp_clauses->chunk_size);
+                 WALK_SUBEXPR (co->ext.omp_clauses->safelen_expr);
+                 WALK_SUBEXPR (co->ext.omp_clauses->simdlen_expr);
+                 WALK_SUBEXPR (co->ext.omp_clauses->num_teams);
+                 WALK_SUBEXPR (co->ext.omp_clauses->device);
+                 WALK_SUBEXPR (co->ext.omp_clauses->thread_limit);
+                 WALK_SUBEXPR (co->ext.omp_clauses->dist_chunk_size);
+                 for (idx = 0;
+                      idx < sizeof (list_types) / sizeof (list_types[0]);
+                      idx++)
+                   for (n = co->ext.omp_clauses->lists[list_types[idx]];
+                        n; n = n->next)
+                     WALK_SUBEXPR (n->expr);
                }
              break;
            default:
              break;
            }
 
-         WALK_SUBEXPR ((*c)->expr1);
-         WALK_SUBEXPR ((*c)->expr2);
-         WALK_SUBEXPR ((*c)->expr3);
-         for (b = (*c)->block; b; b = b->block)
+         WALK_SUBEXPR (co->expr1);
+         WALK_SUBEXPR (co->expr2);
+         WALK_SUBEXPR (co->expr3);
+         WALK_SUBEXPR (co->expr4);
+         for (b = co->block; b; b = b->block)
            {
              WALK_SUBEXPR (b->expr1);
              WALK_SUBEXPR (b->expr2);
              WALK_SUBCODE (b->next);
            }
+
+         if (co->op == EXEC_FORALL)
+           forall_level --;
+
+         if (co->op == EXEC_DO)
+           doloop_level --;
+
+         in_omp_workshare = saved_in_omp_workshare;
        }
     }
   return 0;