From 0192ef204cbc1b80a1da59dae7b275cb7de67c81 Mon Sep 17 00:00:00 2001
From: Mikael Morin <mikael@gcc.gnu.org>
Date: Wed, 4 Jan 2012 14:04:24 +0000
Subject: [PATCH] re PR fortran/50981 ([OOP] Wrong-code for scalarizing
 ELEMENTAL call with absent OPTIONAL argument)

	PR fortran/50981
	* trans.h (struct gfc_ss_info): New field data::scalar::can_be_null_ref
	* trans-array.c: If the reference can be NULL, save the reference
	instead of the value.
	* trans-expr.c (gfc_conv_expr): If we have saved a reference,
	dereference it.

From-SVN: r182874
---
 gcc/fortran/ChangeLog     |  9 +++++++++
 gcc/fortran/trans-array.c | 17 ++++++++++++++---
 gcc/fortran/trans-expr.c  |  5 +++++
 gcc/fortran/trans.h       |  8 ++++++--
 4 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 86de8bdac6eb..3f6c5dcebd7a 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,12 @@
+2012-01-04  Mikael Morin  <mikael@gcc.gnu.org>
+
+	PR fortran/50981
+	* trans.h (struct gfc_ss_info): New field data::scalar::can_be_null_ref
+	* trans-array.c: If the reference can be NULL, save the reference
+	instead of the value.
+	* trans-expr.c (gfc_conv_expr): If we have saved a reference,
+	dereference it.
+
 2012-01-04  Mikael Morin  <mikael@gcc.gnu.org>
 
 	* trans-expr.c (gfc_conv_expr): Move address taking...
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 50e1ee422f90..a9a060d82060 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -2422,10 +2422,21 @@ gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript,
 	  break;
 
 	case GFC_SS_REFERENCE:
-	  /* Scalar argument to elemental procedure.  Evaluate this
-	     now.  */
+	  /* Scalar argument to elemental procedure.  */
 	  gfc_init_se (&se, NULL);
-	  gfc_conv_expr (&se, expr);
+	  if (ss_info->data.scalar.can_be_null_ref)
+	    {
+	      /* If the actual argument can be absent (in other words, it can
+		 be a NULL reference), don't try to evaluate it; pass instead
+		 the reference directly.  */
+	      gfc_conv_expr_reference (&se, expr);
+	    }
+	  else
+	    {
+	      /* Otherwise, evaluate the argument outside the loop and pass
+		 a reference to the value.  */
+	      gfc_conv_expr (&se, expr);
+	    }
 	  gfc_add_block_to_block (&outer_loop->pre, &se.pre);
 	  gfc_add_block_to_block (&outer_loop->post, &se.post);
 	  if (gfc_is_class_scalar_expr (expr))
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 12d382de2f6b..54572fbf3dbb 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -5331,6 +5331,11 @@ gfc_conv_expr (gfc_se * se, gfc_expr * expr)
       /* Substitute a scalar expression evaluated outside the scalarization
          loop.  */
       se->expr = ss_info->data.scalar.value;
+      /* If the reference can be NULL, the value field contains the reference,
+	 not the value the reference points to (see gfc_add_loop_ss_code).  */
+      if (ss_info->data.scalar.can_be_null_ref)
+	se->expr = build_fold_indirect_ref_loc (input_location, se->expr);
+
       se->string_length = ss_info->string_length;
       gfc_advance_se_ss_chain (se);
       return;
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 259a08aae069..61a48172e5c7 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -145,8 +145,9 @@ typedef enum
   GFC_SS_SCALAR,
 
   /* Like GFC_SS_SCALAR it evaluates the expression outside the
-     loop. Is always evaluated as a reference to the temporary.
-     Used for elemental function arguments.  */
+     loop.  Is always evaluated as a reference to the temporary, unless
+     temporary evaluation can result in a NULL pointer dereferencing (case of
+     optional arguments).  Used for elemental function arguments.  */
   GFC_SS_REFERENCE,
 
   /* An array section.  Scalarization indices will be substituted during
@@ -196,6 +197,9 @@ typedef struct gfc_ss_info
     struct
     {
       tree value;
+      /* Tells whether the reference can be null in the GFC_SS_REFERENCE case.
+	 Used to handle elemental procedures' optional arguments.  */
+      bool can_be_null_ref;
     }
     scalar;
 
-- 
GitLab