diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 86de8bdac6eb9c7538488fd9daa4ed285211c03f..3f6c5dcebd7ad7ac544faebe5d46818003f0d4ec 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 50e1ee422f90dedc77822000f72fae2846ad87f4..a9a060d820601002181e1cd105bec518be470136 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 12d382de2f6b7bce54c43eb51a45246c858d37d6..54572fbf3dbb174ae75665d9ea1f516abdb6b254 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 259a08aae069f5bac26aecd8c9e7d6be16549cae..61a48172e5c7b057be7ee61760c702263636516a 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;