aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/fortran/ChangeLog9
-rw-r--r--gcc/fortran/trans-array.c17
-rw-r--r--gcc/fortran/trans-expr.c5
-rw-r--r--gcc/fortran/trans.h8
4 files changed, 34 insertions, 5 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 86de8bd..3f6c5dc 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,5 +1,14 @@
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...
(gfc_conv_expr_reference): ... here.
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 50e1ee4..a9a060d 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 12d382d..54572fb 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 259a08a..61a4817 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;