OSDN Git Service

2010-04-27 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / fortran / trans-stmt.c
index 82ecca8..edffb9b 100644 (file)
@@ -1,5 +1,5 @@
 /* Statement translation -- generate GCC trees from gfc_code.
-   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
    Contributed by Paul Brook <paul@nowt.org>
    and Steven Bosscher <s.bosscher@student.tudelft.nl>
@@ -104,21 +104,21 @@ gfc_trans_label_assign (gfc_code * code)
   /* Start a new block.  */
   gfc_init_se (&se, NULL);
   gfc_start_block (&se.pre);
-  gfc_conv_label_variable (&se, code->expr);
+  gfc_conv_label_variable (&se, code->expr1);
 
   len = GFC_DECL_STRING_LEN (se.expr);
   addr = GFC_DECL_ASSIGN_ADDR (se.expr);
 
-  label_tree = gfc_get_label_decl (code->label);
+  label_tree = gfc_get_label_decl (code->label1);
 
-  if (code->label->defined == ST_LABEL_TARGET)
+  if (code->label1->defined == ST_LABEL_TARGET)
     {
       label_tree = gfc_build_addr_expr (pvoid_type_node, label_tree);
       len_tree = integer_minus_one_node;
     }
   else
     {
-      gfc_expr *format = code->label->format;
+      gfc_expr *format = code->label1->format;
 
       label_len = format->value.character.length;
       len_tree = build_int_cst (NULL_TREE, label_len);
@@ -144,13 +144,13 @@ gfc_trans_goto (gfc_code * code)
   tree tmp;
   gfc_se se;
 
-  if (code->label != NULL)
-    return build1_v (GOTO_EXPR, gfc_get_label_decl (code->label));
+  if (code->label1 != NULL)
+    return build1_v (GOTO_EXPR, gfc_get_label_decl (code->label1));
 
   /* ASSIGNED GOTO.  */
   gfc_init_se (&se, NULL);
   gfc_start_block (&se.pre);
-  gfc_conv_label_variable (&se, code->expr);
+  gfc_conv_label_variable (&se, code->expr1);
   tmp = GFC_DECL_STRING_LEN (se.expr);
   tmp = fold_build2 (NE_EXPR, boolean_type_node, tmp,
                     build_int_cst (TREE_TYPE (tmp), -1));
@@ -159,31 +159,15 @@ gfc_trans_goto (gfc_code * code)
 
   assigned_goto = GFC_DECL_ASSIGN_ADDR (se.expr);
 
-  code = code->block;
-  if (code == NULL)
-    {
-      target = fold_build1 (GOTO_EXPR, void_type_node, assigned_goto);
-      gfc_add_expr_to_block (&se.pre, target);
-      return gfc_finish_block (&se.pre);
-    }
-
-  /* Check the label list.  */
-  do
-    {
-      target = gfc_get_label_decl (code->label);
-      tmp = gfc_build_addr_expr (pvoid_type_node, target);
-      tmp = fold_build2 (EQ_EXPR, boolean_type_node, tmp, assigned_goto);
-      tmp = build3_v (COND_EXPR, tmp,
-                     fold_build1 (GOTO_EXPR, void_type_node, target),
-                     build_empty_stmt ());
-      gfc_add_expr_to_block (&se.pre, tmp);
-      code = code->block;
-    }
-  while (code != NULL);
-  gfc_trans_runtime_check (true, false, boolean_true_node, &se.pre, &loc,
-                          "Assigned label is not in the list");
+  /* We're going to ignore a label list.  It does not really change the
+     statement's semantics (because it is just a further restriction on
+     what's legal code); before, we were comparing label addresses here, but
+     that's a very fragile business and may break with optimization.  So
+     just ignore it.  */
 
-  return gfc_finish_block (&se.pre); 
+  target = fold_build1 (GOTO_EXPR, void_type_node, assigned_goto);
+  gfc_add_expr_to_block (&se.pre, target);
+  return gfc_finish_block (&se.pre);
 }
 
 
@@ -212,8 +196,8 @@ gfc_conv_elemental_dependencies (gfc_se * se, gfc_se * loopse,
   gfc_ss *ss;
   gfc_ss_info *info;
   gfc_symbol *fsym;
+  gfc_ref *ref;
   int n;
-  stmtblock_t block;
   tree data;
   tree offset;
   tree size;
@@ -252,7 +236,7 @@ gfc_conv_elemental_dependencies (gfc_se * se, gfc_se * loopse,
            && gfc_check_fncall_dependency (e, fsym->attr.intent,
                                            sym, arg0, check_variable))
        {
-         tree initial;
+         tree initial, temptype;
          stmtblock_t temp_post;
 
          /* Make a local loopinfo for the temporary creation, so that
@@ -268,54 +252,92 @@ gfc_conv_elemental_dependencies (gfc_se * se, gfc_se * loopse,
          /* Obtain the argument descriptor for unpacking.  */
          gfc_init_se (&parmse, NULL);
          parmse.want_pointer = 1;
+
+         /* The scalarizer introduces some specific peculiarities when
+            handling elemental subroutines; the stride can be needed up to
+            the dim_array - 1, rather than dim_loop - 1 to calculate
+            offsets outside the loop.  For this reason, we make sure that
+            the descriptor has the dimensionality of the array by converting
+            trailing elements into ranges with end = start.  */
+         for (ref = e->ref; ref; ref = ref->next)
+           if (ref->type == REF_ARRAY && ref->u.ar.type == AR_SECTION)
+             break;
+
+         if (ref)
+           {
+             bool seen_range = false;
+             for (n = 0; n < ref->u.ar.dimen; n++)
+               {
+                 if (ref->u.ar.dimen_type[n] == DIMEN_RANGE)
+                   seen_range = true;
+
+                 if (!seen_range
+                       || ref->u.ar.dimen_type[n] != DIMEN_ELEMENT)
+                   continue;
+
+                 ref->u.ar.end[n] = gfc_copy_expr (ref->u.ar.start[n]);
+                 ref->u.ar.dimen_type[n] = DIMEN_RANGE;
+               }
+           }
+
          gfc_conv_expr_descriptor (&parmse, e, gfc_walk_expr (e));
          gfc_add_block_to_block (&se->pre, &parmse.pre);
 
-         /* If we've got INTENT(INOUT), initialize the array temporary with
-            a copy of the values.  */
-         if (fsym->attr.intent == INTENT_INOUT)
+         /* If we've got INTENT(INOUT) or a derived type with INTENT(OUT),
+            initialize the array temporary with a copy of the values.  */
+         if (fsym->attr.intent == INTENT_INOUT
+               || (fsym->ts.type ==BT_DERIVED
+                     && fsym->attr.intent == INTENT_OUT))
            initial = parmse.expr;
          else
            initial = NULL_TREE;
 
-         /* Generate the temporary.  Merge the block so that the
-            declarations are put at the right binding level.  Cleaning up the
-            temporary should be the very last thing done, so we add the code to
-            a new block and add it to se->post as last instructions.  */
+         /* Find the type of the temporary to create; we don't use the type
+            of e itself as this breaks for subcomponent-references in e (where
+            the type of e is that of the final reference, but parmse.expr's
+            type corresponds to the full derived-type).  */
+         /* TODO: Fix this somehow so we don't need a temporary of the whole
+            array but instead only the components referenced.  */
+         temptype = TREE_TYPE (parmse.expr); /* Pointer to descriptor.  */
+         gcc_assert (TREE_CODE (temptype) == POINTER_TYPE);
+         temptype = TREE_TYPE (temptype);
+         temptype = gfc_get_element_type (temptype);
+
+         /* Generate the temporary.  Cleaning up the temporary should be the
+            very last thing done, so we add the code to a new block and add it
+            to se->post as last instructions.  */
          size = gfc_create_var (gfc_array_index_type, NULL);
          data = gfc_create_var (pvoid_type_node, NULL);
-         gfc_start_block (&block);
          gfc_init_block (&temp_post);
-         tmp = gfc_typenode_for_spec (&e->ts);
          tmp = gfc_trans_create_temp_array (&se->pre, &temp_post,
-                                            &tmp_loop, info, tmp,
+                                            &tmp_loop, info, temptype,
                                             initial,
                                             false, true, false,
                                             &arg->expr->where);
          gfc_add_modify (&se->pre, size, tmp);
          tmp = fold_convert (pvoid_type_node, info->data);
          gfc_add_modify (&se->pre, data, tmp);
-         gfc_merge_block_scope (&block);
 
          /* Calculate the offset for the temporary.  */
          offset = gfc_index_zero_node;
          for (n = 0; n < info->dimen; n++)
            {
-             tmp = gfc_conv_descriptor_stride (info->descriptor,
-                                               gfc_rank_cst[n]);
+             tmp = gfc_conv_descriptor_stride_get (info->descriptor,
+                                                   gfc_rank_cst[n]);
              tmp = fold_build2 (MULT_EXPR, gfc_array_index_type,
                                 loopse->loop->from[n], tmp);
              offset = fold_build2 (MINUS_EXPR, gfc_array_index_type,
-                                         offset, tmp);
+                                   offset, tmp);
            }
          info->offset = gfc_create_var (gfc_array_index_type, NULL);     
          gfc_add_modify (&se->pre, info->offset, offset);
 
          /* Copy the result back using unpack.  */
-         tmp = build_call_expr (gfor_fndecl_in_unpack, 2, parmse.expr, data);
+         tmp = build_call_expr_loc (input_location,
+                                gfor_fndecl_in_unpack, 2, parmse.expr, data);
          gfc_add_expr_to_block (&se->post, tmp);
 
-         gfc_add_block_to_block (&se->pre, &parmse.pre);
+         /* parmse.pre is already added above.  */
          gfc_add_block_to_block (&se->post, &parmse.post);
          gfc_add_block_to_block (&se->post, &temp_post);
        }
@@ -326,12 +348,16 @@ gfc_conv_elemental_dependencies (gfc_se * se, gfc_se * loopse,
 /* Translate the CALL statement.  Builds a call to an F95 subroutine.  */
 
 tree
-gfc_trans_call (gfc_code * code, bool dependency_check)
+gfc_trans_call (gfc_code * code, bool dependency_check,
+               tree mask, tree count1, bool invert)
 {
   gfc_se se;
   gfc_ss * ss;
   int has_alternate_specifier;
   gfc_dep_check check_variable;
+  tree index = NULL_TREE;
+  tree maskexpr = NULL_TREE;
+  tree tmp;
 
   /* A CALL starts a new block because the actual arguments may have to
      be evaluated first.  */
@@ -350,8 +376,8 @@ gfc_trans_call (gfc_code * code, bool dependency_check)
 
       /* Translate the call.  */
       has_alternate_specifier
-       = gfc_conv_function_call (&se, code->resolved_sym, code->ext.actual,
-                                 NULL_TREE);
+       = gfc_conv_procedure_call (&se, code->resolved_sym, code->ext.actual,
+                                 code->expr1, NULL_TREE);
 
       /* A subroutine without side-effect, by definition, does nothing!  */
       TREE_SIDE_EFFECTS (se.expr) = 1;
@@ -363,7 +389,7 @@ gfc_trans_call (gfc_code * code, bool dependency_check)
          gfc_symbol *sym;
          select_code = code->next;
          gcc_assert(select_code->op == EXEC_SELECT);
-         sym = select_code->expr->symtree->n.sym;
+         sym = select_code->expr1->symtree->n.sym;
          se.expr = convert (gfc_typenode_for_spec (&sym->ts), se.expr);
          if (sym->backend_decl == NULL)
            sym->backend_decl = gfc_get_symbol_decl (sym);
@@ -399,7 +425,7 @@ gfc_trans_call (gfc_code * code, bool dependency_check)
         subscripts.  This could be prevented in the elemental case  
         as temporaries are handled separatedly 
         (below in gfc_conv_elemental_dependencies).  */
-      gfc_conv_loop_setup (&loop, &code->expr->where);
+      gfc_conv_loop_setup (&loop, &code->expr1->where);
       gfc_mark_ss_chain_used (ss, 1);
 
       /* Convert the arguments, checking for dependencies.  */
@@ -423,10 +449,32 @@ gfc_trans_call (gfc_code * code, bool dependency_check)
       gfc_start_scalarized_body (&loop, &body);
       gfc_init_block (&block);
 
+      if (mask && count1)
+       {
+         /* Form the mask expression according to the mask.  */
+         index = count1;
+         maskexpr = gfc_build_array_ref (mask, index, NULL);
+         if (invert)
+           maskexpr = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (maskexpr),
+                                   maskexpr);
+       }
+
       /* Add the subroutine call to the block.  */
-      gfc_conv_function_call (&loopse, code->resolved_sym, code->ext.actual,
-                             NULL_TREE);
-      gfc_add_expr_to_block (&loopse.pre, loopse.expr);
+      gfc_conv_procedure_call (&loopse, code->resolved_sym,
+                              code->ext.actual, code->expr1,
+                              NULL_TREE);
+
+      if (mask && count1)
+       {
+         tmp = build3_v (COND_EXPR, maskexpr, loopse.expr,
+                         build_empty_stmt (input_location));
+         gfc_add_expr_to_block (&loopse.pre, tmp);
+         tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type,
+                            count1, gfc_index_one_node);
+         gfc_add_modify (&loopse.pre, count1, tmp);
+       }
+      else
+       gfc_add_expr_to_block (&loopse.pre, loopse.expr);
 
       gfc_add_block_to_block (&block, &loopse.pre);
       gfc_add_block_to_block (&block, &loopse.post);
@@ -449,7 +497,7 @@ gfc_trans_call (gfc_code * code, bool dependency_check)
 tree
 gfc_trans_return (gfc_code * code ATTRIBUTE_UNUSED)
 {
-  if (code->expr)
+  if (code->expr1)
     {
       gfc_se se;
       tree tmp;
@@ -463,7 +511,7 @@ gfc_trans_return (gfc_code * code ATTRIBUTE_UNUSED)
       if (!result)
         {
           gfc_warning ("An alternate return at %L without a * dummy argument",
-                        &code->expr->where);
+                        &code->expr1->where);
           return build1_v (GOTO_EXPR, gfc_get_return_label ());
         }
 
@@ -471,7 +519,7 @@ gfc_trans_return (gfc_code * code ATTRIBUTE_UNUSED)
       gfc_init_se (&se, NULL);
       gfc_start_block (&se.pre);
 
-      gfc_conv_expr (&se, code->expr);
+      gfc_conv_expr (&se, code->expr1);
 
       tmp = fold_build2 (MODIFY_EXPR, TREE_TYPE (result), result,
                         fold_convert (TREE_TYPE (result), se.expr));
@@ -502,15 +550,17 @@ gfc_trans_pause (gfc_code * code)
   gfc_start_block (&se.pre);
 
 
-  if (code->expr == NULL)
+  if (code->expr1 == NULL)
     {
       tmp = build_int_cst (gfc_int4_type_node, code->ext.stop_code);
-      tmp = build_call_expr (gfor_fndecl_pause_numeric, 1, tmp);
+      tmp = build_call_expr_loc (input_location,
+                            gfor_fndecl_pause_numeric, 1, tmp);
     }
   else
     {
-      gfc_conv_expr_reference (&se, code->expr);
-      tmp = build_call_expr (gfor_fndecl_pause_string, 2,
+      gfc_conv_expr_reference (&se, code->expr1);
+      tmp = build_call_expr_loc (input_location,
+                            gfor_fndecl_pause_string, 2,
                             se.expr, se.string_length);
     }
 
@@ -526,7 +576,7 @@ gfc_trans_pause (gfc_code * code)
    to a runtime library call.  */
 
 tree
-gfc_trans_stop (gfc_code * code)
+gfc_trans_stop (gfc_code *code, bool error_stop)
 {
   tree gfc_int4_type_node = gfc_get_int_type (4);
   gfc_se se;
@@ -536,17 +586,19 @@ gfc_trans_stop (gfc_code * code)
   gfc_init_se (&se, NULL);
   gfc_start_block (&se.pre);
 
-
-  if (code->expr == NULL)
+  if (code->expr1 == NULL)
     {
       tmp = build_int_cst (gfc_int4_type_node, code->ext.stop_code);
-      tmp = build_call_expr (gfor_fndecl_stop_numeric, 1, tmp);
+      tmp = build_call_expr_loc (input_location,
+                            gfor_fndecl_stop_numeric, 1, tmp);
     }
   else
     {
-      gfc_conv_expr_reference (&se, code->expr);
-      tmp = build_call_expr (gfor_fndecl_stop_string, 2,
-                            se.expr, se.string_length);
+      gfc_conv_expr_reference (&se, code->expr1);
+      tmp = build_call_expr_loc (input_location,
+                            error_stop ? gfor_fndecl_error_stop_string
+                                     : gfor_fndecl_stop_string,
+                            2, se.expr, se.string_length);
     }
 
   gfc_add_expr_to_block (&se.pre, tmp);
@@ -557,6 +609,47 @@ gfc_trans_stop (gfc_code * code)
 }
 
 
+tree
+gfc_trans_sync (gfc_code *code, gfc_exec_op type __attribute__ ((unused)))
+{
+  gfc_se se;
+
+  if ((code->expr1 && (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)) || code->expr2)
+    {
+      gfc_init_se (&se, NULL);
+      gfc_start_block (&se.pre);
+    }
+
+  /* Check SYNC IMAGES(imageset) for valid image index.
+     FIXME: Add a check for image-set arrays. */
+  if (code->expr1 && (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)
+      && code->expr1->rank == 0)
+    {
+      tree cond;
+      gfc_conv_expr (&se, code->expr1);
+      cond = fold_build2 (NE_EXPR, boolean_type_node, se.expr,
+                         build_int_cst (TREE_TYPE (se.expr), 1));
+      gfc_trans_runtime_check (true, false, cond, &se.pre,
+                              &code->expr1->where, "Invalid image number "
+                              "%d in SYNC IMAGES",
+                              fold_convert (integer_type_node, se.expr));
+    }
+
+  /* If STAT is present, set it to zero.  */
+  if (code->expr2)
+    {
+      gcc_assert (code->expr2->expr_type == EXPR_VARIABLE);
+      gfc_conv_expr (&se, code->expr2);
+      gfc_add_modify (&se.pre, se.expr, build_int_cst (TREE_TYPE (se.expr), 0));
+    }
+
+  if ((code->expr1 && (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)) || code->expr2)
+    return gfc_finish_block (&se.pre);
+  return NULL_TREE;
+}
+
+
 /* Generate GENERIC for the IF construct. This function also deals with
    the simple IF statement, because the front end translates the IF
    statement into an IF construct.
@@ -604,7 +697,7 @@ gfc_trans_if_1 (gfc_code * code)
   tree stmt, elsestmt;
 
   /* Check for an unconditional ELSE clause.  */
-  if (!code->expr)
+  if (!code->expr1)
     return gfc_trans_code (code->next);
 
   /* Initialize a statement builder for each block. Puts in NULL_TREEs.  */
@@ -612,7 +705,7 @@ gfc_trans_if_1 (gfc_code * code)
   gfc_start_block (&if_se.pre);
 
   /* Calculate the IF condition expression.  */
-  gfc_conv_expr_val (&if_se, code->expr);
+  gfc_conv_expr_val (&if_se, code->expr1);
 
   /* Translate the THEN clause.  */
   stmt = gfc_trans_code (code->next);
@@ -621,7 +714,7 @@ gfc_trans_if_1 (gfc_code * code)
   if (code->block)
     elsestmt = gfc_trans_if_1 (code->block);
   else
-    elsestmt = build_empty_stmt ();
+    elsestmt = build_empty_stmt (input_location);
 
   /* Build the condition expression and add it to the condition block.  */
   stmt = fold_build3 (COND_EXPR, void_type_node, if_se.expr, stmt, elsestmt);
@@ -679,20 +772,20 @@ gfc_trans_arithmetic_if (gfc_code * code)
   gfc_start_block (&se.pre);
 
   /* Pre-evaluate COND.  */
-  gfc_conv_expr_val (&se, code->expr);
+  gfc_conv_expr_val (&se, code->expr1);
   se.expr = gfc_evaluate_now (se.expr, &se.pre);
 
   /* Build something to compare with.  */
   zero = gfc_build_const (TREE_TYPE (se.expr), integer_zero_node);
 
-  if (code->label->value != code->label2->value)
+  if (code->label1->value != code->label2->value)
     {
       /* If (cond < 0) take branch1 else take branch2.
          First build jumps to the COND .LT. 0 and the COND .EQ. 0 cases.  */
-      branch1 = build1_v (GOTO_EXPR, gfc_get_label_decl (code->label));
+      branch1 = build1_v (GOTO_EXPR, gfc_get_label_decl (code->label1));
       branch2 = build1_v (GOTO_EXPR, gfc_get_label_decl (code->label2));
 
-      if (code->label->value != code->label3->value)
+      if (code->label1->value != code->label3->value)
         tmp = fold_build2 (LT_EXPR, boolean_type_node, se.expr, zero);
       else
         tmp = fold_build2 (NE_EXPR, boolean_type_node, se.expr, zero);
@@ -700,9 +793,9 @@ gfc_trans_arithmetic_if (gfc_code * code)
       branch1 = fold_build3 (COND_EXPR, void_type_node, tmp, branch1, branch2);
     }
   else
-    branch1 = build1_v (GOTO_EXPR, gfc_get_label_decl (code->label));
+    branch1 = build1_v (GOTO_EXPR, gfc_get_label_decl (code->label1));
 
-  if (code->label->value != code->label3->value
+  if (code->label1->value != code->label3->value
       && code->label2->value != code->label3->value)
     {
       /* if (cond <= 0) take branch1 else take branch2.  */
@@ -717,6 +810,51 @@ gfc_trans_arithmetic_if (gfc_code * code)
 }
 
 
+/* Translate a CRITICAL block. */
+tree
+gfc_trans_critical (gfc_code *code)
+{
+  stmtblock_t block;
+  tree tmp;
+
+  gfc_start_block (&block);
+  tmp = gfc_trans_code (code->block->next);
+  gfc_add_expr_to_block (&block, tmp);
+
+  return gfc_finish_block (&block);
+}
+
+
+/* Translate a BLOCK construct.  This is basically what we would do for a
+   procedure body.  */
+
+tree
+gfc_trans_block_construct (gfc_code* code)
+{
+  gfc_namespace* ns;
+  gfc_symbol* sym;
+  stmtblock_t body;
+  tree tmp;
+
+  ns = code->ext.ns;
+  gcc_assert (ns);
+  sym = ns->proc_name;
+  gcc_assert (sym);
+
+  gcc_assert (!sym->tlink);
+  sym->tlink = sym;
+
+  gfc_start_block (&body);
+  gfc_process_block_locals (ns);
+
+  tmp = gfc_trans_code (ns->code);
+  tmp = gfc_trans_deferred_vars (sym, tmp);
+
+  gfc_add_expr_to_block (&body, tmp);
+  return gfc_finish_block (&body);
+}
+
+
 /* Translate the simple DO construct.  This is where the loop variable has
    integer type and step +-1.  We can't use this in the general case
    because integer overflow and floating point errors could give incorrect
@@ -749,12 +887,13 @@ gfc_trans_arithmetic_if (gfc_code * code)
 
 static tree
 gfc_trans_simple_do (gfc_code * code, stmtblock_t *pblock, tree dovar,
-                    tree from, tree to, tree step)
+                    tree from, tree to, tree step, tree exit_cond)
 {
   stmtblock_t body;
   tree type;
   tree cond;
   tree tmp;
+  tree saved_dovar = NULL;
   tree cycle_label;
   tree exit_label;
   
@@ -762,6 +901,13 @@ gfc_trans_simple_do (gfc_code * code, stmtblock_t *pblock, tree dovar,
 
   /* Initialize the DO variable: dovar = from.  */
   gfc_add_modify (pblock, dovar, from);
+  
+  /* Save value for do-tinkering checking. */
+  if (gfc_option.rtcheck & GFC_RTCHECK_DO)
+    {
+      saved_dovar = gfc_create_var (type, ".saved_dovar");
+      gfc_add_modify (pblock, saved_dovar, dovar);
+    }
 
   /* Cycle and exit statements are implemented with gotos.  */
   cycle_label = gfc_build_label_decl (NULL_TREE);
@@ -774,7 +920,7 @@ gfc_trans_simple_do (gfc_code * code, stmtblock_t *pblock, tree dovar,
   gfc_start_block (&body);
 
   /* Main loop body.  */
-  tmp = gfc_trans_code (code->block->next);
+  tmp = gfc_trans_code_cond (code->block->next, exit_cond);
   gfc_add_expr_to_block (&body, tmp);
 
   /* Label for cycle statements (if needed).  */
@@ -784,6 +930,23 @@ gfc_trans_simple_do (gfc_code * code, stmtblock_t *pblock, tree dovar,
       gfc_add_expr_to_block (&body, tmp);
     }
 
+  /* Check whether someone has modified the loop variable. */
+  if (gfc_option.rtcheck & GFC_RTCHECK_DO)
+    {
+      tmp = fold_build2 (NE_EXPR, boolean_type_node, dovar, saved_dovar);
+      gfc_trans_runtime_check (true, false, tmp, &body, &code->loc,
+                              "Loop variable has been modified");
+    }
+
+  /* Exit the loop if there is an I/O result condition or error.  */
+  if (exit_cond)
+    {
+      tmp = build1_v (GOTO_EXPR, exit_label);
+      tmp = fold_build3 (COND_EXPR, void_type_node, exit_cond, tmp,
+                        build_empty_stmt (input_location));
+      gfc_add_expr_to_block (&body, tmp);
+    }
+
   /* Evaluate the loop condition.  */
   cond = fold_build2 (EQ_EXPR, boolean_type_node, dovar, to);
   cond = gfc_evaluate_now (cond, &body);
@@ -792,11 +955,14 @@ gfc_trans_simple_do (gfc_code * code, stmtblock_t *pblock, tree dovar,
   tmp = fold_build2 (PLUS_EXPR, type, dovar, step);
   gfc_add_modify (&body, dovar, tmp);
 
+  if (gfc_option.rtcheck & GFC_RTCHECK_DO)
+    gfc_add_modify (&body, saved_dovar, dovar);
+
   /* The loop exit.  */
   tmp = build1_v (GOTO_EXPR, exit_label);
   TREE_USED (exit_label) = 1;
   tmp = fold_build3 (COND_EXPR, void_type_node,
-                    cond, tmp, build_empty_stmt ());
+                    cond, tmp, build_empty_stmt (input_location));
   gfc_add_expr_to_block (&body, tmp);
 
   /* Finish the loop body.  */
@@ -809,7 +975,7 @@ gfc_trans_simple_do (gfc_code * code, stmtblock_t *pblock, tree dovar,
   else
     cond = fold_build2 (GE_EXPR, boolean_type_node, dovar, to);
   tmp = fold_build3 (COND_EXPR, void_type_node,
-                    cond, tmp, build_empty_stmt ());
+                    cond, tmp, build_empty_stmt (input_location));
   gfc_add_expr_to_block (pblock, tmp);
 
   /* Add the exit label.  */
@@ -854,10 +1020,11 @@ exit_label:
    because the loop count itself can overflow.  */
 
 tree
-gfc_trans_do (gfc_code * code)
+gfc_trans_do (gfc_code * code, tree exit_cond)
 {
   gfc_se se;
   tree dovar;
+  tree saved_dovar = NULL;
   tree from;
   tree to;
   tree step;
@@ -896,11 +1063,19 @@ gfc_trans_do (gfc_code * code)
   gfc_add_block_to_block (&block, &se.pre);
   step = gfc_evaluate_now (se.expr, &block);
 
+  if (gfc_option.rtcheck & GFC_RTCHECK_DO)
+    {
+      tmp = fold_build2 (EQ_EXPR, boolean_type_node, step,
+                        fold_convert (type, integer_zero_node));
+      gfc_trans_runtime_check (true, false, tmp, &block, &code->loc,
+                              "DO step value is zero");
+    }
+
   /* Special case simple loops.  */
   if (TREE_CODE (type) == INTEGER_TYPE
       && (integer_onep (step)
        || tree_int_cst_equal (step, integer_minus_one_node)))
-    return gfc_trans_simple_do (code, &block, dovar, from, to, step);
+    return gfc_trans_simple_do (code, &block, dovar, from, to, step, exit_cond);
 
   pos_step = fold_build2 (GT_EXPR, boolean_type_node, step,
                          fold_convert (type, integer_zero_node));
@@ -919,46 +1094,66 @@ gfc_trans_do (gfc_code * code)
   /* Initialize the DO variable: dovar = from.  */
   gfc_add_modify (&block, dovar, from);
 
+  /* Save value for do-tinkering checking. */
+  if (gfc_option.rtcheck & GFC_RTCHECK_DO)
+    {
+      saved_dovar = gfc_create_var (type, ".saved_dovar");
+      gfc_add_modify (&block, saved_dovar, dovar);
+    }
+
   /* Initialize loop count and jump to exit label if the loop is empty.
      This code is executed before we enter the loop body. We generate:
+     step_sign = sign(1,step);
      if (step > 0)
        {
-        if (to < from) goto exit_label;
-        countm1 = (to - from) / step;
+        if (to < from)
+          goto exit_label;
        }
      else
        {
-        if (to > from) goto exit_label;
-        countm1 = (from - to) / -step;
-       }  */
+        if (to > from)
+          goto exit_label;
+       }
+       countm1 = (to*step_sign - from*step_sign) / (step*step_sign);
+
+  */
+
   if (TREE_CODE (type) == INTEGER_TYPE)
     {
-      tree pos, neg;
+      tree pos, neg, step_sign, to2, from2, step2;
+
+      /* Calculate SIGN (1,step), as (step < 0 ? -1 : 1)  */
+
+      tmp = fold_build2 (LT_EXPR, boolean_type_node, step, 
+                        build_int_cst (TREE_TYPE (step), 0));
+      step_sign = fold_build3 (COND_EXPR, type, tmp, 
+                              build_int_cst (type, -1), 
+                              build_int_cst (type, 1));
 
       tmp = fold_build2 (LT_EXPR, boolean_type_node, to, from);
       pos = fold_build3 (COND_EXPR, void_type_node, tmp,
                         build1_v (GOTO_EXPR, exit_label),
-                        build_empty_stmt ());
-      tmp = fold_build2 (MINUS_EXPR, type, to, from);
-      tmp = fold_convert (utype, tmp);
-      tmp = fold_build2 (TRUNC_DIV_EXPR, utype, tmp,
-                        fold_convert (utype, step));
-      tmp = build2 (MODIFY_EXPR, void_type_node, countm1, tmp);
-      pos = build2 (COMPOUND_EXPR, void_type_node, pos, tmp);
+                        build_empty_stmt (input_location));
 
       tmp = fold_build2 (GT_EXPR, boolean_type_node, to, from);
       neg = fold_build3 (COND_EXPR, void_type_node, tmp,
                         build1_v (GOTO_EXPR, exit_label),
-                        build_empty_stmt ());
-      tmp = fold_build2 (MINUS_EXPR, type, from, to);
-      tmp = fold_convert (utype, tmp);
-      tmp = fold_build2 (TRUNC_DIV_EXPR, utype, tmp,
-                        fold_convert (utype, fold_build1 (NEGATE_EXPR,
-                                                          type, step)));
-      tmp = build2 (MODIFY_EXPR, void_type_node, countm1, tmp);
-      neg = build2 (COMPOUND_EXPR, void_type_node, neg, tmp);
-
+                        build_empty_stmt (input_location));
       tmp = fold_build3 (COND_EXPR, void_type_node, pos_step, pos, neg);
+
+      gfc_add_expr_to_block (&block, tmp);
+
+      /* Calculate the loop count.  to-from can overflow, so
+        we cast to unsigned.  */
+
+      to2 = fold_build2 (MULT_EXPR, type, step_sign, to);
+      from2 = fold_build2 (MULT_EXPR, type, step_sign, from);
+      step2 = fold_build2 (MULT_EXPR, type, step_sign, step);
+      step2 = fold_convert (utype, step2);
+      tmp = fold_build2 (MINUS_EXPR, type, to2, from2);
+      tmp = fold_convert (utype, tmp);
+      tmp = fold_build2 (TRUNC_DIV_EXPR, utype, tmp, step2);
+      tmp = fold_build2 (MODIFY_EXPR, void_type_node, countm1, tmp);
       gfc_add_expr_to_block (&block, tmp);
     }
   else
@@ -980,7 +1175,7 @@ gfc_trans_do (gfc_code * code)
       /* If the loop is empty, go directly to the exit label.  */
       tmp = fold_build3 (COND_EXPR, void_type_node, tmp,
                         build1_v (GOTO_EXPR, exit_label),
-                        build_empty_stmt ());
+                        build_empty_stmt (input_location));
       gfc_add_expr_to_block (&block, tmp);
     }
 
@@ -995,7 +1190,7 @@ gfc_trans_do (gfc_code * code)
   code->block->backend_decl = tree_cons (cycle_label, exit_label, NULL);
 
   /* Main loop body.  */
-  tmp = gfc_trans_code (code->block->next);
+  tmp = gfc_trans_code_cond (code->block->next, exit_cond);
   gfc_add_expr_to_block (&body, tmp);
 
   /* Label for cycle statements (if needed).  */
@@ -1005,16 +1200,36 @@ gfc_trans_do (gfc_code * code)
       gfc_add_expr_to_block (&body, tmp);
     }
 
+  /* Check whether someone has modified the loop variable. */
+  if (gfc_option.rtcheck & GFC_RTCHECK_DO)
+    {
+      tmp = fold_build2 (NE_EXPR, boolean_type_node, dovar, saved_dovar);
+      gfc_trans_runtime_check (true, false, tmp, &body, &code->loc,
+                              "Loop variable has been modified");
+    }
+
+  /* Exit the loop if there is an I/O result condition or error.  */
+  if (exit_cond)
+    {
+      tmp = build1_v (GOTO_EXPR, exit_label);
+      tmp = fold_build3 (COND_EXPR, void_type_node, exit_cond, tmp,
+                        build_empty_stmt (input_location));
+      gfc_add_expr_to_block (&body, tmp);
+    }
+
   /* Increment the loop variable.  */
   tmp = fold_build2 (PLUS_EXPR, type, dovar, step);
   gfc_add_modify (&body, dovar, tmp);
 
+  if (gfc_option.rtcheck & GFC_RTCHECK_DO)
+    gfc_add_modify (&body, saved_dovar, dovar);
+
   /* End with the loop condition.  Loop until countm1 == 0.  */
   cond = fold_build2 (EQ_EXPR, boolean_type_node, countm1,
                      build_int_cst (utype, 0));
   tmp = build1_v (GOTO_EXPR, exit_label);
   tmp = fold_build3 (COND_EXPR, void_type_node,
-                    cond, tmp, build_empty_stmt ());
+                    cond, tmp, build_empty_stmt (input_location));
   gfc_add_expr_to_block (&body, tmp);
 
   /* Decrement the loop count.  */
@@ -1080,7 +1295,7 @@ gfc_trans_do_while (gfc_code * code)
 
   /* Create a GIMPLE version of the exit condition.  */
   gfc_init_se (&cond, NULL);
-  gfc_conv_expr_val (&cond, code->expr);
+  gfc_conv_expr_val (&cond, code->expr1);
   gfc_add_block_to_block (&block, &cond.pre);
   cond.expr = fold_build1 (TRUTH_NOT_EXPR, boolean_type_node, cond.expr);
 
@@ -1088,7 +1303,7 @@ gfc_trans_do_while (gfc_code * code)
   tmp = build1_v (GOTO_EXPR, exit_label);
   TREE_USED (exit_label) = 1;
   tmp = fold_build3 (COND_EXPR, void_type_node,
-                    cond.expr, tmp, build_empty_stmt ());
+                    cond.expr, tmp, build_empty_stmt (input_location));
   gfc_add_expr_to_block (&block, tmp);
 
   /* The main body of the loop.  */
@@ -1178,7 +1393,7 @@ gfc_trans_integer_select (gfc_code * code)
 
   /* Calculate the switch expression.  */
   gfc_init_se (&se, NULL);
-  gfc_conv_expr_val (&se, code->expr);
+  gfc_conv_expr_val (&se, code->expr1);
   gfc_add_block_to_block (&block, &se.pre);
 
   end_label = gfc_build_label_decl (NULL_TREE);
@@ -1319,7 +1534,7 @@ gfc_trans_logical_select (gfc_code * code)
   /* Calculate the switch expression.  We always need to do this
      because it may have side effects.  */
   gfc_init_se (&se, NULL);
-  gfc_conv_expr_val (&se, code->expr);
+  gfc_conv_expr_val (&se, code->expr1);
   gfc_add_block_to_block (&block, &se.pre);
 
   if (t == f && t != NULL)
@@ -1333,8 +1548,8 @@ gfc_trans_logical_select (gfc_code * code)
     {
       tree true_tree, false_tree, stmt;
 
-      true_tree = build_empty_stmt ();
-      false_tree = build_empty_stmt ();
+      true_tree = build_empty_stmt (input_location);
+      false_tree = build_empty_stmt (input_location);
 
       /* If we have a case for .TRUE. and for .FALSE., discard the default case.
           Otherwise, if .TRUE. or .FALSE. is missing and there is a default case,
@@ -1392,11 +1607,11 @@ gfc_trans_character_select (gfc_code *code)
   static tree ss_string2[2], ss_string2_len[2];
   static tree ss_target[2];
 
-  tree pchartype = gfc_get_pchar_type (code->expr->ts.kind);
+  tree pchartype = gfc_get_pchar_type (code->expr1->ts.kind);
 
-  if (code->expr->ts.kind == 1)
+  if (code->expr1->ts.kind == 1)
     k = 0;
-  else if (code->expr->ts.kind == 4)
+  else if (code->expr1->ts.kind == 4)
     k = 1;
   else
     gcc_unreachable ();
@@ -1405,9 +1620,9 @@ gfc_trans_character_select (gfc_code *code)
     {
       select_struct[k] = make_node (RECORD_TYPE);
 
-      if (code->expr->ts.kind == 1)
+      if (code->expr1->ts.kind == 1)
        TYPE_NAME (select_struct[k]) = get_identifier ("_jump_struct_char1");
-      else if (code->expr->ts.kind == 4)
+      else if (code->expr1->ts.kind == 4)
        TYPE_NAME (select_struct[k]) = get_identifier ("_jump_struct_char4");
       else
        gcc_unreachable ();
@@ -1523,18 +1738,19 @@ gfc_trans_character_select (gfc_code *code)
   init = gfc_build_addr_expr (pvoid_type_node, init);
 
   gfc_init_se (&se, NULL);
-  gfc_conv_expr_reference (&se, code->expr);
+  gfc_conv_expr_reference (&se, code->expr1);
 
   gfc_add_block_to_block (&block, &se.pre);
 
-  if (code->expr->ts.kind == 1)
+  if (code->expr1->ts.kind == 1)
     fndecl = gfor_fndecl_select_string;
-  else if (code->expr->ts.kind == 4)
+  else if (code->expr1->ts.kind == 4)
     fndecl = gfor_fndecl_select_string_char4;
   else
     gcc_unreachable ();
 
-  tmp = build_call_expr (fndecl, 4, init, build_int_cst (NULL_TREE, n),
+  tmp = build_call_expr_loc (input_location,
+                        fndecl, 4, init, build_int_cst (NULL_TREE, n),
                         se.expr, se.string_length);
   case_num = gfc_create_var (integer_type_node, "case_num");
   gfc_add_modify (&block, case_num, tmp);
@@ -1569,14 +1785,14 @@ gfc_trans_character_select (gfc_code *code)
 tree
 gfc_trans_select (gfc_code * code)
 {
-  gcc_assert (code && code->expr);
+  gcc_assert (code && code->expr1);
 
   /* Empty SELECT constructs are legal.  */
   if (code->block == NULL)
-    return build_empty_stmt ();
+    return build_empty_stmt (input_location);
 
   /* Select the correct translation function.  */
-  switch (code->expr->ts.type)
+  switch (code->expr1->ts.type)
     {
     case BT_LOGICAL:   return gfc_trans_logical_select (code);
     case BT_INTEGER:   return gfc_trans_integer_select (code);
@@ -1652,23 +1868,22 @@ forall_make_variable_temp (gfc_code *c, stmtblock_t *pre, stmtblock_t *post)
   tree tmp;
 
   /* Build a copy of the lvalue.  */
-  old_symtree = c->expr->symtree;
+  old_symtree = c->expr1->symtree;
   old_sym = old_symtree->n.sym;
   e = gfc_lval_expr_from_sym (old_sym);
   if (old_sym->attr.dimension)
     {
       gfc_init_se (&tse, NULL);
-      gfc_conv_subref_array_arg (&tse, e, 0, INTENT_IN);
+      gfc_conv_subref_array_arg (&tse, e, 0, INTENT_IN, false);
       gfc_add_block_to_block (pre, &tse.pre);
       gfc_add_block_to_block (post, &tse.post);
-      tse.expr = build_fold_indirect_ref (tse.expr);
+      tse.expr = build_fold_indirect_ref_loc (input_location, tse.expr);
 
       if (e->ts.type != BT_CHARACTER)
        {
          /* Use the variable offset for the temporary.  */
-         tmp = gfc_conv_descriptor_offset (tse.expr);
-         gfc_add_modify (pre, tmp,
-               gfc_conv_array_offset (old_sym->backend_decl));
+         tmp = gfc_conv_array_offset (old_sym->backend_decl);
+         gfc_conv_descriptor_offset_set (pre, tse.expr, tmp);
        }
     }
   else
@@ -1693,7 +1908,7 @@ forall_make_variable_temp (gfc_code *c, stmtblock_t *pre, stmtblock_t *post)
        }
 
       tmp = gfc_trans_scalar_assign (&tse, &rse, e->ts, true,
-                                    e->expr_type == EXPR_VARIABLE);
+                                    e->expr_type == EXPR_VARIABLE, true);
       gfc_add_expr_to_block (pre, tmp);
     }
   gfc_free_expr (e);
@@ -1702,6 +1917,7 @@ forall_make_variable_temp (gfc_code *c, stmtblock_t *pre, stmtblock_t *post)
   new_sym = gfc_new_symbol (old_sym->name, NULL);
   new_sym->ts = old_sym->ts;
   new_sym->attr.referenced = 1;
+  new_sym->attr.temporary = 1;
   new_sym->attr.dimension = old_sym->attr.dimension;
   new_sym->attr.flavor = old_sym->attr.flavor;
 
@@ -1716,7 +1932,7 @@ forall_make_variable_temp (gfc_code *c, stmtblock_t *pre, stmtblock_t *post)
 
   /* Go through the expression reference replacing the old_symtree
      with the new.  */
-  forall_replace_symtree (c->expr, old_sym, 2);
+  forall_replace_symtree (c->expr1, old_sym, 2);
 
   /* Now we have made this temporary, we might as well use it for
   the right hand side.  */
@@ -1733,8 +1949,8 @@ check_forall_dependencies (gfc_code *c, stmtblock_t *pre, stmtblock_t *post)
   int need_temp;
   gfc_symbol *lsym;
 
-  lsym = c->expr->symtree->n.sym;
-  need_temp = gfc_check_dependency (c->expr, c->expr2, 0);
+  lsym = c->expr1->symtree->n.sym;
+  need_temp = gfc_check_dependency (c->expr1, c->expr2, 0);
 
   /* Now check for dependencies within the 'variable'
      expression itself.  These are treated by making a complete
@@ -1744,11 +1960,11 @@ check_forall_dependencies (gfc_code *c, stmtblock_t *pre, stmtblock_t *post)
      pointer components.  We therefore leave these to their
      own devices.  */
   if (lsym->ts.type == BT_DERIVED
-       && lsym->ts.derived->attr.pointer_comp)
+       && lsym->ts.u.derived->attr.pointer_comp)
     return need_temp;
 
   new_symtree = NULL;
-  if (find_forall_index (c->expr, lsym, 2) == SUCCESS)
+  if (find_forall_index (c->expr1, lsym, 2) == SUCCESS)
     {
       forall_make_variable_temp (c, pre, post);
       need_temp = 0;
@@ -1756,12 +1972,12 @@ check_forall_dependencies (gfc_code *c, stmtblock_t *pre, stmtblock_t *post)
 
   /* Substrings with dependencies are treated in the same
      way.  */
-  if (c->expr->ts.type == BT_CHARACTER
-       && c->expr->ref
+  if (c->expr1->ts.type == BT_CHARACTER
+       && c->expr1->ref
        && c->expr2->expr_type == EXPR_VARIABLE
        && lsym == c->expr2->symtree->n.sym)
     {
-      for (lref = c->expr->ref; lref; lref = lref->next)
+      for (lref = c->expr1->ref; lref; lref = lref->next)
        if (lref->type == REF_SUBSTRING)
          break;
       for (rref = c->expr2->ref; rref; rref = rref->next)
@@ -1782,7 +1998,7 @@ check_forall_dependencies (gfc_code *c, stmtblock_t *pre, stmtblock_t *post)
 static void
 cleanup_forall_symtrees (gfc_code *c)
 {
-  forall_restore_symtree (c->expr);
+  forall_restore_symtree (c->expr1);
   forall_restore_symtree (c->expr2);
   gfc_free (new_symtree->n.sym);
   gfc_free (new_symtree);
@@ -1848,7 +2064,7 @@ gfc_trans_forall_loop (forall_info *forall_tmp, tree body,
                          count, build_int_cst (TREE_TYPE (count), 0));
       tmp = build1_v (GOTO_EXPR, exit_label);
       tmp = fold_build3 (COND_EXPR, void_type_node,
-                        cond, tmp, build_empty_stmt ());
+                        cond, tmp, build_empty_stmt (input_location));
       gfc_add_expr_to_block (&block, tmp);
 
       /* The main loop body.  */
@@ -1930,7 +2146,8 @@ gfc_trans_nested_forall_loop (forall_info * nested_forall_info, tree body,
           if (mask)
             {
               tmp = gfc_build_array_ref (mask, maskindex, NULL);
-              body = build3_v (COND_EXPR, tmp, body, build_empty_stmt ());
+              body = build3_v (COND_EXPR, tmp, body,
+                              build_empty_stmt (input_location));
             }
         }
       body = gfc_trans_forall_loop (forall_tmp, body, mask_flag, &header);
@@ -2055,7 +2272,7 @@ generate_loop_for_temp_to_lhs (gfc_expr *expr, tree tmp1, tree count3,
 
       /* Use the scalar assignment.  */
       rse.string_length = lse.string_length;
-      tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts, false, false);
+      tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts, false, true, true);
 
       /* Form the mask expression according to the mask tree list.  */
       if (wheremask)
@@ -2066,7 +2283,8 @@ generate_loop_for_temp_to_lhs (gfc_expr *expr, tree tmp1, tree count3,
                                         TREE_TYPE (wheremaskexpr),
                                         wheremaskexpr);
          tmp = fold_build3 (COND_EXPR, void_type_node,
-                            wheremaskexpr, tmp, build_empty_stmt ());
+                            wheremaskexpr, tmp,
+                            build_empty_stmt (input_location));
        }
 
       gfc_add_expr_to_block (&body, tmp);
@@ -2152,7 +2370,7 @@ generate_loop_for_rhs_to_temp (gfc_expr *expr2, tree tmp1, tree count3,
   /* Use the scalar assignment.  */
   lse.string_length = rse.string_length;
   tmp = gfc_trans_scalar_assign (&lse, &rse, expr2->ts, true,
-                                expr2->expr_type == EXPR_VARIABLE);
+                                expr2->expr_type == EXPR_VARIABLE, true);
 
   /* Form the mask expression according to the mask tree list.  */
   if (wheremask)
@@ -2163,7 +2381,7 @@ generate_loop_for_rhs_to_temp (gfc_expr *expr2, tree tmp1, tree count3,
                                     TREE_TYPE (wheremaskexpr),
                                     wheremaskexpr);
       tmp = fold_build3 (COND_EXPR, void_type_node,
-                        wheremaskexpr, tmp, build_empty_stmt ());
+                        wheremaskexpr, tmp, build_empty_stmt (input_location));
     }
 
   gfc_add_expr_to_block (&body1, tmp);
@@ -2252,10 +2470,10 @@ compute_inner_temp_size (gfc_expr *expr1, gfc_expr *expr2,
       loop.array_parameter = 1;
 
       /* Calculate the bounds of the scalarization.  */
-      save_flag = flag_bounds_check;
-      flag_bounds_check = 0;
+      save_flag = gfc_option.rtcheck;
+      gfc_option.rtcheck &= !GFC_RTCHECK_BOUNDS;
       gfc_conv_ss_startstride (&loop);
-      flag_bounds_check = save_flag;
+      gfc_option.rtcheck = save_flag;
       gfc_conv_loop_setup (&loop, &expr2->where);
 
       /* Figure out how many elements we need.  */
@@ -2359,7 +2577,7 @@ allocate_temp_for_forall_nest_1 (tree type, tree size, stmtblock_t * block,
   tmp = gfc_do_allocate (bytesize, size, ptemp1, block, type);
 
   if (*ptemp1)
-    tmp = build_fold_indirect_ref (tmp);
+    tmp = build_fold_indirect_ref_loc (input_location, tmp);
   return tmp;
 }
 
@@ -2451,17 +2669,17 @@ gfc_trans_assign_need_temp (gfc_expr * expr1, gfc_expr * expr2,
                                        &lss, &rss);
 
   /* The type of LHS. Used in function allocate_temp_for_forall_nest */
-  if (expr1->ts.type == BT_CHARACTER && expr1->ts.cl->length)
+  if (expr1->ts.type == BT_CHARACTER && expr1->ts.u.cl->length)
     {
-      if (!expr1->ts.cl->backend_decl)
+      if (!expr1->ts.u.cl->backend_decl)
        {
          gfc_se tse;
          gfc_init_se (&tse, NULL);
-         gfc_conv_expr (&tse, expr1->ts.cl->length);
-         expr1->ts.cl->backend_decl = tse.expr;
+         gfc_conv_expr (&tse, expr1->ts.u.cl->length);
+         expr1->ts.u.cl->backend_decl = tse.expr;
        }
       type = gfc_get_character_type_len (gfc_default_character_kind,
-                                        expr1->ts.cl->backend_decl);
+                                        expr1->ts.u.cl->backend_decl);
     }
   else
     type = gfc_typenode_for_spec (&expr1->ts);
@@ -2604,9 +2822,9 @@ gfc_trans_pointer_assign_need_temp (gfc_expr * expr1, gfc_expr * expr2,
 
       /* Make a new descriptor.  */
       parmtype = gfc_get_element_type (TREE_TYPE (desc));
-      parmtype = gfc_get_array_type_bounds (parmtype, loop.dimen,
+      parmtype = gfc_get_array_type_bounds (parmtype, loop.dimen, 0,
                                             loop.from, loop.to, 1,
-                                           GFC_ARRAY_UNKNOWN);
+                                           GFC_ARRAY_UNKNOWN, true);
 
       /* Allocate temporary for nested forall construct.  */
       tmp1 = allocate_temp_for_forall_nest (nested_forall_info, parmtype,
@@ -2732,10 +2950,10 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info)
   bool need_mask;
 
   /* Do nothing if the mask is false.  */
-  if (code->expr
-      && code->expr->expr_type == EXPR_CONSTANT
-      && !code->expr->value.logical)
-    return build_empty_stmt ();
+  if (code->expr1
+      && code->expr1->expr_type == EXPR_CONSTANT
+      && !code->expr1->value.logical)
+    return build_empty_stmt (input_location);
 
   n = 0;
   /* Count the FORALL index number.  */
@@ -2837,11 +3055,11 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info)
   info->nvar = nvar;
   info->size = size;
 
-  if (code->expr)
+  if (code->expr1)
     {
       /* If the mask is .true., consider the FORALL unconditional.  */
-      if (code->expr->expr_type == EXPR_CONSTANT
-         && code->expr->value.logical)
+      if (code->expr1->expr_type == EXPR_CONSTANT
+         && code->expr1->value.logical)
        need_mask = false;
       else
        need_mask = true;
@@ -2887,7 +3105,7 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info)
 
       /* Evaluate the mask expression.  */
       gfc_init_se (&se, NULL);
-      gfc_conv_expr_val (&se, code->expr);
+      gfc_conv_expr_val (&se, code->expr1);
       gfc_add_block_to_block (&body, &se.pre);
 
       /* Store the mask.  */
@@ -2924,12 +3142,12 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info)
           /* Temporaries due to array assignment data dependencies introduce
              no end of problems.  */
          if (need_temp)
-            gfc_trans_assign_need_temp (c->expr, c->expr2, NULL, false,
+            gfc_trans_assign_need_temp (c->expr1, c->expr2, NULL, false,
                                         nested_forall_info, &block);
           else
             {
               /* Use the normal assignment copying routines.  */
-              assign = gfc_trans_assignment (c->expr, c->expr2, false);
+              assign = gfc_trans_assignment (c->expr1, c->expr2, false, true);
 
               /* Generate body and loops.  */
               tmp = gfc_trans_nested_forall_loop (nested_forall_info,
@@ -2951,14 +3169,14 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info)
 
         /* Pointer assignment inside FORALL.  */
        case EXEC_POINTER_ASSIGN:
-          need_temp = gfc_check_dependency (c->expr, c->expr2, 0);
+          need_temp = gfc_check_dependency (c->expr1, c->expr2, 0);
           if (need_temp)
-            gfc_trans_pointer_assign_need_temp (c->expr, c->expr2,
+            gfc_trans_pointer_assign_need_temp (c->expr1, c->expr2,
                                                 nested_forall_info, &block);
           else
             {
               /* Use the normal assignment copying routines.  */
-              assign = gfc_trans_pointer_assignment (c->expr, c->expr2);
+              assign = gfc_trans_pointer_assignment (c->expr1, c->expr2);
 
               /* Generate body and loops.  */
               tmp = gfc_trans_nested_forall_loop (nested_forall_info,
@@ -2975,7 +3193,7 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info)
        /* Explicit subroutine calls are prevented by the frontend but interface
           assignments can legitimately produce them.  */
        case EXEC_ASSIGN_CALL:
-         assign = gfc_trans_call (c, true);
+         assign = gfc_trans_call (c, true, NULL_TREE, NULL_TREE, false);
           tmp = gfc_trans_nested_forall_loop (nested_forall_info, assign, 1);
           gfc_add_expr_to_block (&block, tmp);
           break;
@@ -3170,7 +3388,7 @@ static tree
 gfc_trans_where_assign (gfc_expr *expr1, gfc_expr *expr2,
                        tree mask, bool invert,
                         tree count1, tree count2,
-                       gfc_symbol *sym)
+                       gfc_code *cnext)
 {
   gfc_se lse;
   gfc_se rse;
@@ -3184,6 +3402,10 @@ gfc_trans_where_assign (gfc_expr *expr1, gfc_expr *expr2,
   stmtblock_t body;
   tree index, maskexpr;
 
+  /* A defined assignment. */  
+  if (cnext && cnext->resolved_sym)
+    return gfc_trans_call (cnext, true, mask, count1, invert);
+
 #if 0
   /* TODO: handle this special case.
      Special case a single function returning an array.  */
@@ -3285,13 +3507,10 @@ gfc_trans_where_assign (gfc_expr *expr1, gfc_expr *expr2,
     maskexpr = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (maskexpr), maskexpr);
 
   /* Use the scalar assignment as is.  */
-  if (sym == NULL)
-    tmp = gfc_trans_scalar_assign (&lse, &rse, expr1->ts,
-                                  loop.temp_ss != NULL, false);
-  else
-    tmp = gfc_conv_operator_assign (&lse, &rse, sym);
+  tmp = gfc_trans_scalar_assign (&lse, &rse, expr1->ts,
+                                loop.temp_ss != NULL, false, true);
 
-  tmp = build3_v (COND_EXPR, maskexpr, tmp, build_empty_stmt ());
+  tmp = build3_v (COND_EXPR, maskexpr, tmp, build_empty_stmt (input_location));
 
   gfc_add_expr_to_block (&body, tmp);
 
@@ -3343,8 +3562,10 @@ gfc_trans_where_assign (gfc_expr *expr1, gfc_expr *expr2,
                                    maskexpr);
 
           /* Use the scalar assignment as is.  */
-          tmp = gfc_trans_scalar_assign (&lse, &rse, expr1->ts, false, false);
-          tmp = build3_v (COND_EXPR, maskexpr, tmp, build_empty_stmt ());
+          tmp = gfc_trans_scalar_assign (&lse, &rse, expr1->ts, false, false,
+                                        true);
+          tmp = build3_v (COND_EXPR, maskexpr, tmp,
+                         build_empty_stmt (input_location));
           gfc_add_expr_to_block (&body, tmp);
 
           /* Increment count2.  */
@@ -3437,7 +3658,7 @@ gfc_trans_where_2 (gfc_code * code, tree mask, bool invert,
   /* Two clauses, the first empty, the second non-empty.  */
   else if (mask)
     {
-      need_cmask = (cblock->block->expr != 0);
+      need_cmask = (cblock->block->expr1 != 0);
       need_pmask = true;
     }
   else
@@ -3450,7 +3671,7 @@ gfc_trans_where_2 (gfc_code * code, tree mask, bool invert,
     {
       /* Calculate the size of temporary needed by the mask-expr.  */
       gfc_init_block (&inner_size_body);
-      inner_size = compute_inner_temp_size (cblock->expr, cblock->expr,
+      inner_size = compute_inner_temp_size (cblock->expr1, cblock->expr1,
                                            &inner_size_body, &lss, &rss);
 
       /* Calculate the total size of temporary needed.  */
@@ -3482,7 +3703,7 @@ gfc_trans_where_2 (gfc_code * code, tree mask, bool invert,
         bottom of the loop.  */
 
       /* Has mask-expr.  */
-      if (cblock->expr)
+      if (cblock->expr1)
         {
           /* Ensure that the WHERE mask will be evaluated exactly once.
             If there are no statements in this WHERE/ELSEWHERE clause,
@@ -3490,13 +3711,13 @@ gfc_trans_where_2 (gfc_code * code, tree mask, bool invert,
             If this is the last clause of the WHERE construct, then
             we don't need to update the pending control mask (pmask).  */
          if (mask)
-           gfc_evaluate_where_mask (cblock->expr, nested_forall_info,
+           gfc_evaluate_where_mask (cblock->expr1, nested_forall_info,
                                     mask, invert,
                                     cblock->next  ? cmask : NULL_TREE,
                                     cblock->block ? pmask : NULL_TREE,
                                     mask_type, block);
          else
-           gfc_evaluate_where_mask (cblock->expr, nested_forall_info,
+           gfc_evaluate_where_mask (cblock->expr1, nested_forall_info,
                                     NULL_TREE, false,
                                     (cblock->next || cblock->block)
                                     ? cmask : NULL_TREE,
@@ -3535,7 +3756,7 @@ gfc_trans_where_2 (gfc_code * code, tree mask, bool invert,
              goto evaluate;
 
             case EXEC_ASSIGN:
-              expr1 = cnext->expr;
+              expr1 = cnext->expr1;
               expr2 = cnext->expr2;
     evaluate:
               if (nested_forall_info != NULL)
@@ -3556,7 +3777,7 @@ gfc_trans_where_2 (gfc_code * code, tree mask, bool invert,
                       tmp = gfc_trans_where_assign (expr1, expr2,
                                                    cmask, invert,
                                                    count1, count2,
-                                                   cnext->resolved_sym);
+                                                   cnext);
 
                       tmp = gfc_trans_nested_forall_loop (nested_forall_info,
                                                           tmp, 1);
@@ -3574,7 +3795,7 @@ gfc_trans_where_2 (gfc_code * code, tree mask, bool invert,
                   tmp = gfc_trans_where_assign (expr1, expr2,
                                                cmask, invert,
                                                count1, count2,
-                                               cnext->resolved_sym);
+                                               cnext);
                   gfc_add_expr_to_block (block, tmp);
 
                 }
@@ -3643,10 +3864,14 @@ gfc_trans_where_3 (gfc_code * cblock, gfc_code * eblock)
   gfc_ss *edss = 0;
   gfc_ss *esss = 0;
 
-  cond = cblock->expr;
-  tdst = cblock->next->expr;
+  /* Allow the scalarizer to workshare simple where loops.  */
+  if (ompws_flags & OMPWS_WORKSHARE_FLAG)
+    ompws_flags |= OMPWS_SCALARIZER_WS;
+
+  cond = cblock->expr1;
+  tdst = cblock->next->expr1;
   tsrc = cblock->next->expr2;
-  edst = eblock ? eblock->next->expr : NULL;
+  edst = eblock ? eblock->next->expr1 : NULL;
   esrc = eblock ? eblock->next->expr2 : NULL;
 
   gfc_start_block (&block);
@@ -3745,9 +3970,10 @@ gfc_trans_where_3 (gfc_code * cblock, gfc_code * eblock)
         gfc_conv_expr (&edse, edst);
     }
 
-  tstmt = gfc_trans_scalar_assign (&tdse, &tsse, tdst->ts, false, false);
-  estmt = eblock ? gfc_trans_scalar_assign (&edse, &esse, edst->ts, false, false)
-                : build_empty_stmt ();
+  tstmt = gfc_trans_scalar_assign (&tdse, &tsse, tdst->ts, false, false, true);
+  estmt = eblock ? gfc_trans_scalar_assign (&edse, &esse, edst->ts, false,
+                                           false, true)
+                : build_empty_stmt (input_location);
   tmp = build3_v (COND_EXPR, cexpr, tstmt, estmt);
   gfc_add_expr_to_block (&body, tmp);
   gfc_add_block_to_block (&body, &cse.post);
@@ -3782,13 +4008,13 @@ gfc_trans_where (gfc_code * code)
           /* A simple "WHERE (cond) x = y" statement or block is
             dependence free if cond is not dependent upon writing x,
             and the source y is unaffected by the destination x.  */
-         if (!gfc_check_dependency (cblock->next->expr,
-                                    cblock->expr, 0)
-             && !gfc_check_dependency (cblock->next->expr,
+         if (!gfc_check_dependency (cblock->next->expr1,
+                                    cblock->expr1, 0)
+             && !gfc_check_dependency (cblock->next->expr1,
                                        cblock->next->expr2, 0))
            return gfc_trans_where_3 (cblock, NULL);
        }
-      else if (!eblock->expr
+      else if (!eblock->expr1
               && !eblock->block
               && eblock->next
               && eblock->next->op == EXEC_ASSIGN
@@ -3804,22 +4030,22 @@ gfc_trans_where (gfc_code * code)
             are the same.  In short, this is VERY conservative and this
             is needed because the two loops, required by the standard
             are coalesced in gfc_trans_where_3.  */
-         if (!gfc_check_dependency(cblock->next->expr,
-                                   cblock->expr, 0)
-             && !gfc_check_dependency(eblock->next->expr,
-                                      cblock->expr, 0)
-             && !gfc_check_dependency(cblock->next->expr,
+         if (!gfc_check_dependency(cblock->next->expr1,
+                                   cblock->expr1, 0)
+             && !gfc_check_dependency(eblock->next->expr1,
+                                      cblock->expr1, 0)
+             && !gfc_check_dependency(cblock->next->expr1,
                                       eblock->next->expr2, 1)
-             && !gfc_check_dependency(eblock->next->expr,
+             && !gfc_check_dependency(eblock->next->expr1,
                                       cblock->next->expr2, 1)
-             && !gfc_check_dependency(cblock->next->expr,
+             && !gfc_check_dependency(cblock->next->expr1,
                                       cblock->next->expr2, 1)
-             && !gfc_check_dependency(eblock->next->expr,
+             && !gfc_check_dependency(eblock->next->expr1,
                                       eblock->next->expr2, 1)
-             && !gfc_check_dependency(cblock->next->expr,
-                                      eblock->next->expr, 0)
-             && !gfc_check_dependency(eblock->next->expr,
-                                      cblock->next->expr, 0))
+             && !gfc_check_dependency(cblock->next->expr1,
+                                      eblock->next->expr1, 0)
+             && !gfc_check_dependency(eblock->next->expr1,
+                                      cblock->next->expr1, 0))
            return gfc_trans_where_3 (cblock, eblock);
        }
     }
@@ -3875,29 +4101,34 @@ gfc_trans_allocate (gfc_code * code)
   tree stat;
   tree pstat;
   tree error_label;
+  tree memsz;
   stmtblock_t block;
 
-  if (!code->ext.alloc_list)
+  if (!code->ext.alloc.list)
     return NULL_TREE;
 
+  pstat = stat = error_label = tmp = memsz = NULL_TREE;
+
   gfc_start_block (&block);
 
-  if (code->expr)
+  /* Either STAT= and/or ERRMSG is present.  */
+  if (code->expr1 || code->expr2)
     {
       tree gfc_int4_type_node = gfc_get_int_type (4);
 
       stat = gfc_create_var (gfc_int4_type_node, "stat");
-      pstat = build_fold_addr_expr (stat);
+      pstat = gfc_build_addr_expr (NULL_TREE, stat);
 
       error_label = gfc_build_label_decl (NULL_TREE);
       TREE_USED (error_label) = 1;
     }
-  else
-    pstat = stat = error_label = NULL_TREE;
 
-  for (al = code->ext.alloc_list; al != NULL; al = al->next)
+  for (al = code->ext.alloc.list; al != NULL; al = al->next)
     {
-      expr = al->expr;
+      expr = gfc_copy_expr (al->expr);
+
+      if (expr->ts.type == BT_CLASS)
+       gfc_add_component_ref (expr, "$data");
 
       gfc_init_se (&se, NULL);
       gfc_start_block (&se.pre);
@@ -3909,30 +4140,74 @@ gfc_trans_allocate (gfc_code * code)
       if (!gfc_array_allocate (&se, expr, pstat))
        {
          /* A scalar or derived type.  */
-         tmp = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (se.expr)));
 
-         if (expr->ts.type == BT_CHARACTER && tmp == NULL_TREE)
-           tmp = se.string_length;
+         /* Determine allocate size.  */
+         if (code->expr3 && code->expr3->ts.type == BT_CLASS)
+           {
+             gfc_expr *sz;
+             gfc_se se_sz;
+             sz = gfc_copy_expr (code->expr3);
+             gfc_add_component_ref (sz, "$vptr");
+             gfc_add_component_ref (sz, "$size");
+             gfc_init_se (&se_sz, NULL);
+             gfc_conv_expr (&se_sz, sz);
+             gfc_free_expr (sz);
+             memsz = se_sz.expr;
+           }
+         else if (code->expr3 && code->expr3->ts.type != BT_CLASS)
+           memsz = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->expr3->ts));
+         else if (code->ext.alloc.ts.type != BT_UNKNOWN)
+           memsz = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->ext.alloc.ts));
+         else
+           memsz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (se.expr)));
+
+         if (expr->ts.type == BT_CHARACTER && memsz == NULL_TREE)
+           memsz = se.string_length;
+
+         /* Allocate - for non-pointers with re-alloc checking.  */
+         {
+           gfc_ref *ref;
+           bool allocatable;
+
+           ref = expr->ref;
+
+           /* Find the last reference in the chain.  */
+           while (ref && ref->next != NULL)
+             {
+               gcc_assert (ref->type != REF_ARRAY || ref->u.ar.type == AR_ELEMENT);
+               ref = ref->next;
+             }
+
+           if (!ref)
+             allocatable = expr->symtree->n.sym->attr.allocatable;
+           else
+             allocatable = ref->u.c.component->attr.allocatable;
+
+           if (allocatable)
+             tmp = gfc_allocate_array_with_status (&se.pre, se.expr, memsz,
+                                                   pstat, expr);
+           else
+             tmp = gfc_allocate_with_status (&se.pre, memsz, pstat);
+         }
 
-         tmp = gfc_allocate_with_status (&se.pre, tmp, pstat);
          tmp = fold_build2 (MODIFY_EXPR, void_type_node, se.expr,
                             fold_convert (TREE_TYPE (se.expr), tmp));
          gfc_add_expr_to_block (&se.pre, tmp);
 
-         if (code->expr)
+         if (code->expr1 || code->expr2)
            {
              tmp = build1_v (GOTO_EXPR, error_label);
              parm = fold_build2 (NE_EXPR, boolean_type_node,
                                  stat, build_int_cst (TREE_TYPE (stat), 0));
              tmp = fold_build3 (COND_EXPR, void_type_node,
-                                parm, tmp, build_empty_stmt ());
+                                parm, tmp, build_empty_stmt (input_location));
              gfc_add_expr_to_block (&se.pre, tmp);
            }
 
-         if (expr->ts.type == BT_DERIVED && expr->ts.derived->attr.alloc_comp)
+         if (expr->ts.type == BT_DERIVED && expr->ts.u.derived->attr.alloc_comp)
            {
-             tmp = build_fold_indirect_ref (se.expr);
-             tmp = gfc_nullify_alloc_comp (expr->ts.derived, tmp, 0);
+             tmp = build_fold_indirect_ref_loc (input_location, se.expr);
+             tmp = gfc_nullify_alloc_comp (expr->ts.u.derived, tmp, 0);
              gfc_add_expr_to_block (&se.pre, tmp);
            }
 
@@ -3940,43 +4215,136 @@ gfc_trans_allocate (gfc_code * code)
 
       tmp = gfc_finish_block (&se.pre);
       gfc_add_expr_to_block (&block, tmp);
+
+      /* Initialization via SOURCE block.  */
+      if (code->expr3)
+       {
+         gfc_expr *rhs = gfc_copy_expr (code->expr3);
+         if (al->expr->ts.type == BT_CLASS)
+           {
+             gfc_se dst,src;
+             if (rhs->ts.type == BT_CLASS)
+               gfc_add_component_ref (rhs, "$data");
+             gfc_init_se (&dst, NULL);
+             gfc_init_se (&src, NULL);
+             gfc_conv_expr (&dst, expr);
+             gfc_conv_expr (&src, rhs);
+             gfc_add_block_to_block (&block, &src.pre);
+             tmp = gfc_build_memcpy_call (dst.expr, src.expr, memsz);
+           }
+         else
+           tmp = gfc_trans_assignment (gfc_expr_to_initialize (expr),
+                                       rhs, false, false);
+         gfc_free_expr (rhs);
+         gfc_add_expr_to_block (&block, tmp);
+       }
+
+      /* Allocation of CLASS entities.  */
+      gfc_free_expr (expr);
+      expr = al->expr;
+      if (expr->ts.type == BT_CLASS)
+       {
+         gfc_expr *lhs,*rhs;
+         gfc_se lse;
+
+         /* Initialize VPTR for CLASS objects.  */
+         lhs = gfc_expr_to_initialize (expr);
+         gfc_add_component_ref (lhs, "$vptr");
+         rhs = NULL;
+         if (code->expr3 && code->expr3->ts.type == BT_CLASS)
+           {
+             /* VPTR must be determined at run time.  */
+             rhs = gfc_copy_expr (code->expr3);
+             gfc_add_component_ref (rhs, "$vptr");
+             tmp = gfc_trans_pointer_assignment (lhs, rhs);
+             gfc_add_expr_to_block (&block, tmp);
+             gfc_free_expr (rhs);
+           }
+         else
+           {
+             /* VPTR is fixed at compile time.  */
+             gfc_symbol *vtab;
+             gfc_typespec *ts;
+             if (code->expr3)
+               ts = &code->expr3->ts;
+             else if (expr->ts.type == BT_DERIVED)
+               ts = &expr->ts;
+             else if (code->ext.alloc.ts.type == BT_DERIVED)
+               ts = &code->ext.alloc.ts;
+             else if (expr->ts.type == BT_CLASS)
+               ts = &expr->ts.u.derived->components->ts;
+             else
+               ts = &expr->ts;
+
+             if (ts->type == BT_DERIVED)
+               {
+                 vtab = gfc_find_derived_vtab (ts->u.derived);
+                 gcc_assert (vtab);
+                 gfc_init_se (&lse, NULL);
+                 lse.want_pointer = 1;
+                 gfc_conv_expr (&lse, lhs);
+                 tmp = gfc_build_addr_expr (NULL_TREE,
+                                            gfc_get_symbol_decl (vtab));
+                 gfc_add_modify (&block, lse.expr,
+                       fold_convert (TREE_TYPE (lse.expr), tmp));
+               }
+           }
+       }
+
     }
 
-  /* Assign the value to the status variable.  */
-  if (code->expr)
+  /* STAT block.  */
+  if (code->expr1)
     {
       tmp = build1_v (LABEL_EXPR, error_label);
       gfc_add_expr_to_block (&block, tmp);
 
       gfc_init_se (&se, NULL);
-      gfc_conv_expr_lhs (&se, code->expr);
+      gfc_conv_expr_lhs (&se, code->expr1);
       tmp = convert (TREE_TYPE (se.expr), stat);
       gfc_add_modify (&block, se.expr, tmp);
     }
 
+  /* ERRMSG block.  */
+  if (code->expr2)
+    {
+      /* A better error message may be possible, but not required.  */
+      const char *msg = "Attempt to allocate an allocated object";
+      tree errmsg, slen, dlen;
+
+      gfc_init_se (&se, NULL);
+      gfc_conv_expr_lhs (&se, code->expr2);
+
+      errmsg = gfc_create_var (pchar_type_node, "ERRMSG");
+
+      gfc_add_modify (&block, errmsg,
+               gfc_build_addr_expr (pchar_type_node,
+                       gfc_build_localized_cstring_const (msg)));
+
+      slen = build_int_cst (gfc_charlen_type_node, ((int) strlen (msg)));
+      dlen = gfc_get_expr_charlen (code->expr2);
+      slen = fold_build2 (MIN_EXPR, TREE_TYPE (slen), dlen, slen);
+
+      dlen = build_call_expr_loc (input_location,
+                             built_in_decls[BUILT_IN_MEMCPY], 3,
+               gfc_build_addr_expr (pvoid_type_node, se.expr), errmsg, slen);
+
+      tmp = fold_build2 (NE_EXPR, boolean_type_node, stat,
+                        build_int_cst (TREE_TYPE (stat), 0));
+
+      tmp = build3_v (COND_EXPR, tmp, dlen, build_empty_stmt (input_location));
+
+      gfc_add_expr_to_block (&block, tmp);
+    }
+
   return gfc_finish_block (&block);
 }
 
 
-/* Translate a DEALLOCATE statement.
-   There are two cases within the for loop:
-   (1) deallocate(a1, a2, a3) is translated into the following sequence
-       _gfortran_deallocate(a1, 0B)
-       _gfortran_deallocate(a2, 0B)
-       _gfortran_deallocate(a3, 0B)
-       where the STAT= variable is passed a NULL pointer.
-   (2) deallocate(a1, a2, a3, stat=i) is translated into the following
-       astat = 0
-       _gfortran_deallocate(a1, &stat)
-       astat = astat + stat
-       _gfortran_deallocate(a2, &stat)
-       astat = astat + stat
-       _gfortran_deallocate(a3, &stat)
-       astat = astat + stat
-    In case (1), we simply return at the end of the for loop.  In case (2)
-    we set STAT= astat.  */
+/* Translate a DEALLOCATE statement.  */
+
 tree
-gfc_trans_deallocate (gfc_code * code)
+gfc_trans_deallocate (gfc_code *code)
 {
   gfc_se se;
   gfc_alloc *al;
@@ -3984,28 +4352,29 @@ gfc_trans_deallocate (gfc_code * code)
   tree apstat, astat, pstat, stat, tmp;
   stmtblock_t block;
 
+  pstat = apstat = stat = astat = tmp = NULL_TREE;
+
   gfc_start_block (&block);
 
-  /* Set up the optional STAT= */
-  if (code->expr)
+  /* Count the number of failed deallocations.  If deallocate() was
+     called with STAT= , then set STAT to the count.  If deallocate
+     was called with ERRMSG, then set ERRMG to a string.  */
+  if (code->expr1 || code->expr2)
     {
       tree gfc_int4_type_node = gfc_get_int_type (4);
 
-      /* Variable used with the library call.  */
       stat = gfc_create_var (gfc_int4_type_node, "stat");
-      pstat = build_fold_addr_expr (stat);
+      pstat = gfc_build_addr_expr (NULL_TREE, stat);
 
       /* Running total of possible deallocation failures.  */
       astat = gfc_create_var (gfc_int4_type_node, "astat");
-      apstat = build_fold_addr_expr (astat);
+      apstat = gfc_build_addr_expr (NULL_TREE, astat);
 
       /* Initialize astat to 0.  */
       gfc_add_modify (&block, astat, build_int_cst (TREE_TYPE (astat), 0));
     }
-  else
-    pstat = apstat = stat = astat = NULL_TREE;
 
-  for (al = code->ext.alloc_list; al != NULL; al = al->next)
+  for (al = code->ext.alloc.list; al != NULL; al = al->next)
     {
       expr = al->expr;
       gcc_assert (expr->expr_type == EXPR_VARIABLE);
@@ -4017,8 +4386,7 @@ gfc_trans_deallocate (gfc_code * code)
       se.descriptor_only = 1;
       gfc_conv_expr (&se, expr);
 
-      if (expr->ts.type == BT_DERIVED
-           && expr->ts.derived->attr.alloc_comp)
+      if (expr->ts.type == BT_DERIVED && expr->ts.u.derived->attr.alloc_comp)
         {
          gfc_ref *ref;
          gfc_ref *last = NULL;
@@ -4029,9 +4397,9 @@ gfc_trans_deallocate (gfc_code * code)
          /* Do not deallocate the components of a derived type
             ultimate pointer component.  */
          if (!(last && last->u.c.component->attr.pointer)
-                  && !(!last && expr->symtree->n.sym->attr.pointer))
+               && !(!last && expr->symtree->n.sym->attr.pointer))
            {
-             tmp = gfc_deallocate_alloc_comp (expr->ts.derived, se.expr,
+             tmp = gfc_deallocate_alloc_comp (expr->ts.u.derived, se.expr,
                                               expr->rank);
              gfc_add_expr_to_block (&se.pre, tmp);
            }
@@ -4052,7 +4420,7 @@ gfc_trans_deallocate (gfc_code * code)
 
       /* Keep track of the number of failed deallocations by adding stat
         of the last deallocation to the running total.  */
-      if (code->expr)
+      if (code->expr1 || code->expr2)
        {
          apstat = fold_build2 (PLUS_EXPR, TREE_TYPE (stat), astat, stat);
          gfc_add_modify (&se.pre, astat, apstat);
@@ -4063,15 +4431,47 @@ gfc_trans_deallocate (gfc_code * code)
 
     }
 
-  /* Assign the value to the status variable.  */
-  if (code->expr)
+  /* Set STAT.  */
+  if (code->expr1)
     {
       gfc_init_se (&se, NULL);
-      gfc_conv_expr_lhs (&se, code->expr);
+      gfc_conv_expr_lhs (&se, code->expr1);
       tmp = convert (TREE_TYPE (se.expr), astat);
       gfc_add_modify (&block, se.expr, tmp);
     }
 
+  /* Set ERRMSG.  */
+  if (code->expr2)
+    {
+      /* A better error message may be possible, but not required.  */
+      const char *msg = "Attempt to deallocate an unallocated object";
+      tree errmsg, slen, dlen;
+
+      gfc_init_se (&se, NULL);
+      gfc_conv_expr_lhs (&se, code->expr2);
+
+      errmsg = gfc_create_var (pchar_type_node, "ERRMSG");
+
+      gfc_add_modify (&block, errmsg,
+               gfc_build_addr_expr (pchar_type_node,
+                        gfc_build_localized_cstring_const (msg)));
+
+      slen = build_int_cst (gfc_charlen_type_node, ((int) strlen (msg)));
+      dlen = gfc_get_expr_charlen (code->expr2);
+      slen = fold_build2 (MIN_EXPR, TREE_TYPE (slen), dlen, slen);
+
+      dlen = build_call_expr_loc (input_location,
+                             built_in_decls[BUILT_IN_MEMCPY], 3,
+               gfc_build_addr_expr (pvoid_type_node, se.expr), errmsg, slen);
+
+      tmp = fold_build2 (NE_EXPR, boolean_type_node, astat,
+                        build_int_cst (TREE_TYPE (astat), 0));
+
+      tmp = build3_v (COND_EXPR, tmp, dlen, build_empty_stmt (input_location));
+
+      gfc_add_expr_to_block (&block, tmp);
+    }
+
   return gfc_finish_block (&block);
 }