diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index f80c9db..3db38eb 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -3355,7 +3355,7 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
   gfc_symbol *sym;
   gfc_formal_arglist *f;
   stmtblock_t tmpblock;
-  bool seen_trans_deferred_array = false;
+  bool seen_trans_deferred_array = false, processed_proc = false;
   tree tmp = NULL;
   gfc_expr *e;
   gfc_se se;
@@ -3391,37 +3391,8 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
 	}
       else if (proc_sym->ts.type == BT_CHARACTER)
 	{
-	  if (proc_sym->ts.deferred)
-	    {
-	      tmp = NULL;
-	      gfc_save_backend_locus (&loc);
-	      gfc_set_backend_locus (&proc_sym->declared_at);
-	      gfc_start_block (&init);
-	      /* Zero the string length on entry.  */
-	      gfc_add_modify (&init, proc_sym->ts.u.cl->backend_decl,
-			      build_int_cst (gfc_charlen_type_node, 0));
-	      /* Null the pointer.  */
-	      e = gfc_lval_expr_from_sym (proc_sym);
-	      gfc_init_se (&se, NULL);
-	      se.want_pointer = 1;
-	      gfc_conv_expr (&se, e);
-	      gfc_free_expr (e);
-	      tmp = se.expr;
-	      gfc_add_modify (&init, tmp,
-			      fold_convert (TREE_TYPE (se.expr),
-					    null_pointer_node));
-	      gfc_restore_backend_locus (&loc);
-
-	      /* Pass back the string length on exit.  */
-	      tmp = proc_sym->ts.u.cl->passed_length;
-	      tmp = build_fold_indirect_ref_loc (input_location, tmp);
-	      tmp = fold_convert (gfc_charlen_type_node, tmp);
-	      tmp = fold_build2_loc (input_location, MODIFY_EXPR,
-				     gfc_charlen_type_node, tmp,
-				     proc_sym->ts.u.cl->backend_decl);
-	      gfc_add_init_cleanup (block, gfc_finish_block (&init), tmp);
-	    }
-	  else if (TREE_CODE (proc_sym->ts.u.cl->backend_decl) == VAR_DECL)
+	  if (TREE_CODE (proc_sym->ts.u.cl->backend_decl) == VAR_DECL
+	      && !proc_sym->ts.deferred)
 	    gfc_trans_dummy_character (proc_sym, proc_sym->ts.u.cl, block);
 	}
       else
@@ -3437,14 +3408,32 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
   init_intent_out_dt (proc_sym, block);
   gfc_restore_backend_locus (&loc);
 
-  for (sym = proc_sym->tlink; sym != proc_sym; sym = sym->tlink)
+  for (sym = proc_sym->tlink; ; sym = sym->tlink)
     {
       bool sym_has_alloc_comp = (sym->ts.type == BT_DERIVED)
 				   && sym->ts.u.derived->attr.alloc_comp;
       if (sym->assoc)
 	continue;
 
-      if (sym->attr.dimension)
+      /* Handle sym == proc_sym only once to avoid an endless loop.  */
+      if (sym == proc_sym)
+	{
+	  if (processed_proc)
+	    break;
+	  processed_proc = true;
+	}
+
+      /* For function results, which do not need an initialization,
+	 end the loop.  */
+      if (sym == proc_sym
+	  && (sym != proc_sym->result
+	      || !(sym->attr.allocatable || sym->ts.deferred
+		   || sym_has_alloc_comp
+		   || (sym->ts.type == BT_CLASS
+		       && CLASS_DATA (sym)->attr.allocatable))))
+	break;
+
+      if (sym->attr.dimension && sym != proc_sym)
 	{
 	  switch (sym->as->type)
 	    {
@@ -3521,7 +3510,7 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
 	  if (sym_has_alloc_comp && !seen_trans_deferred_array)
 	    gfc_trans_deferred_array (sym, block);
 	}
-      else if ((!sym->attr.dummy || sym->ts.deferred)
+      else if (! sym->attr.dimension && (!sym->attr.dummy || sym->ts.deferred)
 		&& (sym->attr.allocatable
 		    || (sym->ts.type == BT_CLASS
 			&& CLASS_DATA (sym)->attr.allocatable)))
@@ -3551,9 +3540,9 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
 					        null_pointer_node));
 		}
 
-	      if ((sym->attr.dummy ||sym->attr.result)
-		    && sym->ts.type == BT_CHARACTER
-		    && sym->ts.deferred)
+	      if ((sym->attr.dummy || sym->attr.result || sym == proc_sym)
+		  && sym->ts.type == BT_CHARACTER
+		  && sym->ts.deferred)
 		{
 		  /* Character length passed by reference.  */
 		  tmp = sym->ts.u.cl->passed_length;
@@ -3582,7 +3571,7 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
 
 	      /* Deallocate when leaving the scope. Nullifying is not
 		 needed.  */
-	      if (!sym->attr.result && !sym->attr.dummy)
+	      if (!sym->attr.result && sym != proc_sym && !sym->attr.dummy)
 		tmp = gfc_deallocate_scalar_with_status (se.expr, NULL, true,
 							 NULL, sym->ts);
 
@@ -3638,9 +3627,9 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
 	}
       else if (sym->ts.deferred)
 	gfc_fatal_error ("Deferred type parameter not yet supported");
-      else if (sym_has_alloc_comp)
+      else if (sym_has_alloc_comp && proc_sym != sym)
 	gfc_trans_deferred_array (sym, block);
-      else if (sym->ts.type == BT_CHARACTER)
+      else if (sym->ts.type == BT_CHARACTER && sym != proc_sym)
 	{
 	  gfc_save_backend_locus (&loc);
 	  gfc_set_backend_locus (&sym->declared_at);
@@ -3667,7 +3656,7 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
 	  gfc_add_init_cleanup (block, gfc_finish_block (&tmpblock),
 				NULL_TREE);
 	}
-      else
+      else if (proc_sym != sym)
 	gcc_unreachable ();
     }
 
