aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/trans-intrinsic.c
diff options
context:
space:
mode:
authorThomas Koenig <tkoenig@gcc.gnu.org>2018-12-31 14:59:46 +0000
committerThomas Koenig <tkoenig@gcc.gnu.org>2018-12-31 14:59:46 +0000
commit2ea47ee9fd022b611cf238f0b58aafd8472b6913 (patch)
tree824955b15d51902f297b77d070bd8eb211c3d4d2 /gcc/fortran/trans-intrinsic.c
parent4d73e47bf8dbe9829a5d3bec2a5d5df4c62ec11f (diff)
downloadgcc-2ea47ee9fd022b611cf238f0b58aafd8472b6913.zip
gcc-2ea47ee9fd022b611cf238f0b58aafd8472b6913.tar.gz
gcc-2ea47ee9fd022b611cf238f0b58aafd8472b6913.tar.bz2
re PR fortran/82995 (Segmentation fault passing optional argument to intrinsic sum function)
2018-12-31 Thomas Koenig <tkoenig@gcc.gnu.org> PR fortran/82995 * trans-expr.c (gfc_conv_procedure_call): Pass NULL pointer for missing optional dummy arguments for library routines. * trans-intinsic.c (conv_mask_condition): New function. (gfc_conv_intrinsic_arith): Detect and handle optional mask. (gfc_conv_intrinsic_minmaxloc): Likewise. (gfc_conv_intrinsic_findloc): Likewise. (gfc_conv_intrinsic_minmaxval): Likewise. (gfc_inline_intrinsic_function_p): Do not inline for rank > 1 if an optional mask is present. 2018-12-31 Thomas Koenig <tkoenig@gcc.gnu.org> PR fortran/82995 * m4/ifindloc0.m4: Handle case of absend optional argument, passed as a NULL pointer. Correct allocation of retarray->base_addr. * m4/ifindloc1.m4: Likewise. * m4/ifindloc2.m4: Handle case of absend optional argument, passed as a NULL pointer. * m4/iforeach-s.m4: Likewise. * m4/iforeach-s2.m4: Likewise. * m4/iforeach.m4: Likewise. * m4/ifunction-s.m4: Likewise. * m4/ifunction-s2.m4: Likewise. * m4/ifunction.m4: Likewise. * generated/findloc0_c16.c: Regenerated. * generated/findloc0_c4.c: Regenerated. * generated/findloc0_c8.c: Regenerated. * generated/findloc0_i1.c: Regenerated. * generated/findloc0_i16.c: Regenerated. * generated/findloc0_i2.c: Regenerated. * generated/findloc0_i4.c: Regenerated. * generated/findloc0_i8.c: Regenerated. * generated/findloc0_r16.c: Regenerated. * generated/findloc0_r4.c: Regenerated. * generated/findloc0_r8.c: Regenerated. * generated/findloc0_s1.c: Regenerated. * generated/findloc0_s4.c: Regenerated. * generated/findloc1_c16.c: Regenerated. * generated/findloc1_c4.c: Regenerated. * generated/findloc1_c8.c: Regenerated. * generated/findloc1_i1.c: Regenerated. * generated/findloc1_i16.c: Regenerated. * generated/findloc1_i2.c: Regenerated. * generated/findloc1_i4.c: Regenerated. * generated/findloc1_i8.c: Regenerated. * generated/findloc1_r16.c: Regenerated. * generated/findloc1_r4.c: Regenerated. * generated/findloc1_r8.c: Regenerated. * generated/findloc1_s1.c: Regenerated. * generated/findloc1_s4.c: Regenerated. * generated/findloc2_s1.c: Regenerated. * generated/findloc2_s4.c: Regenerated. * generated/iall_i1.c: Regenerated. * generated/iall_i16.c: Regenerated. * generated/iall_i2.c: Regenerated. * generated/iall_i4.c: Regenerated. * generated/iall_i8.c: Regenerated. * generated/iany_i1.c: Regenerated. * generated/iany_i16.c: Regenerated. * generated/iany_i2.c: Regenerated. * generated/iany_i4.c: Regenerated. * generated/iany_i8.c: Regenerated. * generated/iparity_i1.c: Regenerated. * generated/iparity_i16.c: Regenerated. * generated/iparity_i2.c: Regenerated. * generated/iparity_i4.c: Regenerated. * generated/iparity_i8.c: Regenerated. * generated/maxloc0_16_i1.c: Regenerated. * generated/maxloc0_16_i16.c: Regenerated. * generated/maxloc0_16_i2.c: Regenerated. * generated/maxloc0_16_i4.c: Regenerated. * generated/maxloc0_16_i8.c: Regenerated. * generated/maxloc0_16_r10.c: Regenerated. * generated/maxloc0_16_r16.c: Regenerated. * generated/maxloc0_16_r4.c: Regenerated. * generated/maxloc0_16_r8.c: Regenerated. * generated/maxloc0_16_s1.c: Regenerated. * generated/maxloc0_16_s4.c: Regenerated. * generated/maxloc0_4_i1.c: Regenerated. * generated/maxloc0_4_i16.c: Regenerated. * generated/maxloc0_4_i2.c: Regenerated. * generated/maxloc0_4_i4.c: Regenerated. * generated/maxloc0_4_i8.c: Regenerated. * generated/maxloc0_4_r10.c: Regenerated. * generated/maxloc0_4_r16.c: Regenerated. * generated/maxloc0_4_r4.c: Regenerated. * generated/maxloc0_4_r8.c: Regenerated. * generated/maxloc0_4_s1.c: Regenerated. * generated/maxloc0_4_s4.c: Regenerated. * generated/maxloc0_8_i1.c: Regenerated. * generated/maxloc0_8_i16.c: Regenerated. * generated/maxloc0_8_i2.c: Regenerated. * generated/maxloc0_8_i4.c: Regenerated. * generated/maxloc0_8_i8.c: Regenerated. * generated/maxloc0_8_r10.c: Regenerated. * generated/maxloc0_8_r16.c: Regenerated. * generated/maxloc0_8_r4.c: Regenerated. * generated/maxloc0_8_r8.c: Regenerated. * generated/maxloc0_8_s1.c: Regenerated. * generated/maxloc0_8_s4.c: Regenerated. * generated/maxloc1_16_i1.c: Regenerated. * generated/maxloc1_16_i16.c: Regenerated. * generated/maxloc1_16_i2.c: Regenerated. * generated/maxloc1_16_i4.c: Regenerated. * generated/maxloc1_16_i8.c: Regenerated. * generated/maxloc1_16_r10.c: Regenerated. * generated/maxloc1_16_r16.c: Regenerated. * generated/maxloc1_16_r4.c: Regenerated. * generated/maxloc1_16_r8.c: Regenerated. * generated/maxloc1_16_s1.c: Regenerated. * generated/maxloc1_16_s4.c: Regenerated. * generated/maxloc1_4_i1.c: Regenerated. * generated/maxloc1_4_i16.c: Regenerated. * generated/maxloc1_4_i2.c: Regenerated. * generated/maxloc1_4_i4.c: Regenerated. * generated/maxloc1_4_i8.c: Regenerated. * generated/maxloc1_4_r10.c: Regenerated. * generated/maxloc1_4_r16.c: Regenerated. * generated/maxloc1_4_r4.c: Regenerated. * generated/maxloc1_4_r8.c: Regenerated. * generated/maxloc1_4_s1.c: Regenerated. * generated/maxloc1_4_s4.c: Regenerated. * generated/maxloc1_8_i1.c: Regenerated. * generated/maxloc1_8_i16.c: Regenerated. * generated/maxloc1_8_i2.c: Regenerated. * generated/maxloc1_8_i4.c: Regenerated. * generated/maxloc1_8_i8.c: Regenerated. * generated/maxloc1_8_r10.c: Regenerated. * generated/maxloc1_8_r16.c: Regenerated. * generated/maxloc1_8_r4.c: Regenerated. * generated/maxloc1_8_r8.c: Regenerated. * generated/maxloc1_8_s1.c: Regenerated. * generated/maxloc1_8_s4.c: Regenerated. * generated/maxval0_s1.c: Regenerated. * generated/maxval0_s4.c: Regenerated. * generated/maxval1_s1.c: Regenerated. * generated/maxval1_s4.c: Regenerated. * generated/maxval_i1.c: Regenerated. * generated/maxval_i16.c: Regenerated. * generated/maxval_i2.c: Regenerated. * generated/maxval_i4.c: Regenerated. * generated/maxval_i8.c: Regenerated. * generated/maxval_r10.c: Regenerated. * generated/maxval_r16.c: Regenerated. * generated/maxval_r4.c: Regenerated. * generated/maxval_r8.c: Regenerated. * generated/minloc0_16_i1.c: Regenerated. * generated/minloc0_16_i16.c: Regenerated. * generated/minloc0_16_i2.c: Regenerated. * generated/minloc0_16_i4.c: Regenerated. * generated/minloc0_16_i8.c: Regenerated. * generated/minloc0_16_r10.c: Regenerated. * generated/minloc0_16_r16.c: Regenerated. * generated/minloc0_16_r4.c: Regenerated. * generated/minloc0_16_r8.c: Regenerated. * generated/minloc0_16_s1.c: Regenerated. * generated/minloc0_16_s4.c: Regenerated. * generated/minloc0_4_i1.c: Regenerated. * generated/minloc0_4_i16.c: Regenerated. * generated/minloc0_4_i2.c: Regenerated. * generated/minloc0_4_i4.c: Regenerated. * generated/minloc0_4_i8.c: Regenerated. * generated/minloc0_4_r10.c: Regenerated. * generated/minloc0_4_r16.c: Regenerated. * generated/minloc0_4_r4.c: Regenerated. * generated/minloc0_4_r8.c: Regenerated. * generated/minloc0_4_s1.c: Regenerated. * generated/minloc0_4_s4.c: Regenerated. * generated/minloc0_8_i1.c: Regenerated. * generated/minloc0_8_i16.c: Regenerated. * generated/minloc0_8_i2.c: Regenerated. * generated/minloc0_8_i4.c: Regenerated. * generated/minloc0_8_i8.c: Regenerated. * generated/minloc0_8_r10.c: Regenerated. * generated/minloc0_8_r16.c: Regenerated. * generated/minloc0_8_r4.c: Regenerated. * generated/minloc0_8_r8.c: Regenerated. * generated/minloc0_8_s1.c: Regenerated. * generated/minloc0_8_s4.c: Regenerated. * generated/minloc1_16_i1.c: Regenerated. * generated/minloc1_16_i16.c: Regenerated. * generated/minloc1_16_i2.c: Regenerated. * generated/minloc1_16_i4.c: Regenerated. * generated/minloc1_16_i8.c: Regenerated. * generated/minloc1_16_r10.c: Regenerated. * generated/minloc1_16_r16.c: Regenerated. * generated/minloc1_16_r4.c: Regenerated. * generated/minloc1_16_r8.c: Regenerated. * generated/minloc1_16_s1.c: Regenerated. * generated/minloc1_16_s4.c: Regenerated. * generated/minloc1_4_i1.c: Regenerated. * generated/minloc1_4_i16.c: Regenerated. * generated/minloc1_4_i2.c: Regenerated. * generated/minloc1_4_i4.c: Regenerated. * generated/minloc1_4_i8.c: Regenerated. * generated/minloc1_4_r10.c: Regenerated. * generated/minloc1_4_r16.c: Regenerated. * generated/minloc1_4_r4.c: Regenerated. * generated/minloc1_4_r8.c: Regenerated. * generated/minloc1_4_s1.c: Regenerated. * generated/minloc1_4_s4.c: Regenerated. * generated/minloc1_8_i1.c: Regenerated. * generated/minloc1_8_i16.c: Regenerated. * generated/minloc1_8_i2.c: Regenerated. * generated/minloc1_8_i4.c: Regenerated. * generated/minloc1_8_i8.c: Regenerated. * generated/minloc1_8_r10.c: Regenerated. * generated/minloc1_8_r16.c: Regenerated. * generated/minloc1_8_r4.c: Regenerated. * generated/minloc1_8_r8.c: Regenerated. * generated/minloc1_8_s1.c: Regenerated. * generated/minloc1_8_s4.c: Regenerated. * generated/minval0_s1.c: Regenerated. * generated/minval0_s4.c: Regenerated. * generated/minval1_s1.c: Regenerated. * generated/minval1_s4.c: Regenerated. * generated/minval_i1.c: Regenerated. * generated/minval_i16.c: Regenerated. * generated/minval_i2.c: Regenerated. * generated/minval_i4.c: Regenerated. * generated/minval_i8.c: Regenerated. * generated/minval_r10.c: Regenerated. * generated/minval_r16.c: Regenerated. * generated/minval_r4.c: Regenerated. * generated/minval_r8.c: Regenerated. * generated/product_c10.c: Regenerated. * generated/product_c16.c: Regenerated. * generated/product_c4.c: Regenerated. * generated/product_c8.c: Regenerated. * generated/product_i1.c: Regenerated. * generated/product_i16.c: Regenerated. * generated/product_i2.c: Regenerated. * generated/product_i4.c: Regenerated. * generated/product_i8.c: Regenerated. * generated/product_r10.c: Regenerated. * generated/product_r16.c: Regenerated. * generated/product_r4.c: Regenerated. * generated/product_r8.c: Regenerated. * generated/sum_c10.c: Regenerated. * generated/sum_c16.c: Regenerated. * generated/sum_c4.c: Regenerated. * generated/sum_c8.c: Regenerated. * generated/sum_i1.c: Regenerated. * generated/sum_i16.c: Regenerated. * generated/sum_i2.c: Regenerated. * generated/sum_i4.c: Regenerated. * generated/sum_i8.c: Regenerated. * generated/sum_r10.c: Regenerated. * generated/sum_r16.c: Regenerated. * generated/sum_r4.c: Regenerated. * generated/sum_r8.c: Regenerated. 2018-12-31 Thomas Koenig <tkoenig@gcc.gnu.org> PR fortran/82995 * gfortran.dg/optional_absent_4.f90: New test. * gfortran.dg/optional_absent_5.f90: New test. From-SVN: r267487
Diffstat (limited to 'gcc/fortran/trans-intrinsic.c')
-rw-r--r--gcc/fortran/trans-intrinsic.c179
1 files changed, 149 insertions, 30 deletions
diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c
index 40a7491..473334e 100644
--- a/gcc/fortran/trans-intrinsic.c
+++ b/gcc/fortran/trans-intrinsic.c
@@ -4359,6 +4359,28 @@ enter_nested_loop (gfc_se *se)
return se->ss->loop;
}
+/* Build the condition for a mask, which may be optional. */
+
+static tree
+conv_mask_condition (gfc_se *maskse, gfc_expr *maskexpr,
+ bool optional_mask)
+{
+ tree present;
+ tree type;
+
+ if (optional_mask)
+ {
+ type = TREE_TYPE (maskse->expr);
+ present = gfc_conv_expr_present (maskexpr->symtree->n.sym);
+ present = convert (type, present);
+ present = fold_build1_loc (input_location, TRUTH_NOT_EXPR, type,
+ present);
+ return fold_build2_loc (input_location, TRUTH_ORIF_EXPR,
+ type, present, maskse->expr);
+ }
+ else
+ return maskse->expr;
+}
/* Inline implementation of the sum and product intrinsics. */
static void
@@ -4380,6 +4402,7 @@ gfc_conv_intrinsic_arith (gfc_se * se, gfc_expr * expr, enum tree_code op,
gfc_se *parent_se;
gfc_expr *arrayexpr;
gfc_expr *maskexpr;
+ bool optional_mask;
if (expr->rank > 0)
{
@@ -4419,13 +4442,19 @@ gfc_conv_intrinsic_arith (gfc_se * se, gfc_expr * expr, enum tree_code op,
arrayexpr = arg_array->expr;
if (op == NE_EXPR || norm2)
- /* PARITY and NORM2. */
- maskexpr = NULL;
+ {
+ /* PARITY and NORM2. */
+ maskexpr = NULL;
+ optional_mask = false;
+ }
else
{
arg_mask = arg_array->next->next;
gcc_assert (arg_mask != NULL);
maskexpr = arg_mask->expr;
+ optional_mask = maskexpr && maskexpr->expr_type == EXPR_VARIABLE
+ && maskexpr->symtree->n.sym->attr.dummy
+ && maskexpr->symtree->n.sym->attr.optional;
}
if (expr->rank == 0)
@@ -4444,17 +4473,22 @@ gfc_conv_intrinsic_arith (gfc_se * se, gfc_expr * expr, enum tree_code op,
/* Initialize the scalarizer. */
gfc_init_loopinfo (&loop);
- gfc_add_ss_to_loop (&loop, arrayss);
+
+ /* We add the mask first because the number of iterations is
+ taken from the last ss, and this breaks if an absent
+ optional argument is used for mask. */
+
if (maskexpr && maskexpr->rank > 0)
gfc_add_ss_to_loop (&loop, maskss);
+ gfc_add_ss_to_loop (&loop, arrayss);
/* Initialize the loop. */
gfc_conv_ss_startstride (&loop);
gfc_conv_loop_setup (&loop, &expr->where);
- gfc_mark_ss_chain_used (arrayss, 1);
if (maskexpr && maskexpr->rank > 0)
gfc_mark_ss_chain_used (maskss, 1);
+ gfc_mark_ss_chain_used (arrayss, 1);
ploop = &loop;
}
@@ -4563,10 +4597,13 @@ gfc_conv_intrinsic_arith (gfc_se * se, gfc_expr * expr, enum tree_code op,
if (maskexpr && maskexpr->rank > 0)
{
- /* We enclose the above in if (mask) {...} . */
-
+ /* We enclose the above in if (mask) {...} . If the mask is an
+ optional argument, generate
+ IF (.NOT. PRESENT(MASK) .OR. MASK(I)). */
+ tree ifmask;
tmp = gfc_finish_block (&block);
- tmp = build3_v (COND_EXPR, maskse.expr, tmp,
+ ifmask = conv_mask_condition (&maskse, maskexpr, optional_mask);
+ tmp = build3_v (COND_EXPR, ifmask, tmp,
build_empty_stmt (input_location));
}
else
@@ -4591,10 +4628,13 @@ gfc_conv_intrinsic_arith (gfc_se * se, gfc_expr * expr, enum tree_code op,
}
else
{
+ tree ifmask;
+
gcc_assert (expr->rank == 0);
gfc_init_se (&maskse, NULL);
gfc_conv_expr_val (&maskse, maskexpr);
- tmp = build3_v (COND_EXPR, maskse.expr, tmp,
+ ifmask = conv_mask_condition (&maskse, maskexpr, optional_mask);
+ tmp = build3_v (COND_EXPR, ifmask, tmp,
build_empty_stmt (input_location));
}
@@ -4833,6 +4873,7 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op)
gfc_se backse;
tree pos;
int n;
+ bool optional_mask;
actual = expr->value.function.actual;
@@ -4887,6 +4928,9 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op)
actual = actual->next->next;
gcc_assert (actual);
maskexpr = actual->expr;
+ optional_mask = maskexpr && maskexpr->expr_type == EXPR_VARIABLE
+ && maskexpr->symtree->n.sym->attr.dummy
+ && maskexpr->symtree->n.sym->attr.optional;
backexpr = actual->next->next->expr;
nonempty = NULL;
if (maskexpr && maskexpr->rank != 0)
@@ -4939,10 +4983,16 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op)
/* Initialize the scalarizer. */
gfc_init_loopinfo (&loop);
- gfc_add_ss_to_loop (&loop, arrayss);
+
+ /* We add the mask first because the number of iterations is taken
+ from the last ss, and this breaks if an absent optional argument
+ is used for mask. */
+
if (maskss)
gfc_add_ss_to_loop (&loop, maskss);
+ gfc_add_ss_to_loop (&loop, arrayss);
+
/* Initialize the loop. */
gfc_conv_ss_startstride (&loop);
@@ -5103,10 +5153,14 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op)
if (maskss)
{
- /* We enclose the above in if (mask) {...}. */
- tmp = gfc_finish_block (&block);
+ /* We enclose the above in if (mask) {...}. If the mask is an
+ optional argument, generate IF (.NOT. PRESENT(MASK)
+ .OR. MASK(I)). */
- tmp = build3_v (COND_EXPR, maskse.expr, tmp,
+ tree ifmask;
+ ifmask = conv_mask_condition (&maskse, maskexpr, optional_mask);
+ tmp = gfc_finish_block (&block);
+ tmp = build3_v (COND_EXPR, ifmask, tmp,
build_empty_stmt (input_location));
}
else
@@ -5197,10 +5251,14 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op)
if (maskss)
{
- /* We enclose the above in if (mask) {...}. */
- tmp = gfc_finish_block (&block);
+ /* We enclose the above in if (mask) {...}. If the mask is
+ an optional argument, generate IF (.NOT. PRESENT(MASK)
+ .OR. MASK(I)).*/
- tmp = build3_v (COND_EXPR, maskse.expr, tmp,
+ tree ifmask;
+ ifmask = conv_mask_condition (&maskse, maskexpr, optional_mask);
+ tmp = gfc_finish_block (&block);
+ tmp = build3_v (COND_EXPR, ifmask, tmp,
build_empty_stmt (input_location));
}
else
@@ -5219,6 +5277,8 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op)
/* For a scalar mask, enclose the loop in an if statement. */
if (maskexpr && maskss == NULL)
{
+ tree ifmask;
+
gfc_init_se (&maskse, NULL);
gfc_conv_expr_val (&maskse, maskexpr);
gfc_init_block (&block);
@@ -5232,8 +5292,8 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op)
gfc_init_block (&elseblock);
gfc_add_modify (&elseblock, pos, gfc_index_zero_node);
elsetmp = gfc_finish_block (&elseblock);
-
- tmp = build3_v (COND_EXPR, maskse.expr, tmp, elsetmp);
+ ifmask = conv_mask_condition (&maskse, maskexpr, optional_mask);
+ tmp = build3_v (COND_EXPR, ifmask, tmp, elsetmp);
gfc_add_expr_to_block (&block, tmp);
gfc_add_block_to_block (&se->pre, &block);
}
@@ -5276,6 +5336,7 @@ gfc_conv_intrinsic_findloc (gfc_se *se, gfc_expr *expr)
gfc_expr *maskexpr;
tree offset;
int i;
+ bool optional_mask;
array_arg = expr->value.function.actual;
value_arg = array_arg->next;
@@ -5326,6 +5387,9 @@ gfc_conv_intrinsic_findloc (gfc_se *se, gfc_expr *expr)
offset = gfc_create_var (gfc_array_index_type, "offset");
maskexpr = mask_arg->expr;
+ optional_mask = maskexpr && maskexpr->expr_type == EXPR_VARIABLE
+ && maskexpr->symtree->n.sym->attr.dummy
+ && maskexpr->symtree->n.sym->attr.optional;
/* Generate two loops, one for BACK=.true. and one for BACK=.false. */
@@ -5347,9 +5411,14 @@ gfc_conv_intrinsic_findloc (gfc_se *se, gfc_expr *expr)
gfc_init_loopinfo (&loop);
exit_label = gfc_build_label_decl (NULL_TREE);
TREE_USED (exit_label) = 1;
- gfc_add_ss_to_loop (&loop, arrayss);
+
+ /* We add the mask first because the number of iterations is
+ taken from the last ss, and this breaks if an absent
+ optional argument is used for mask. */
+
if (maskss)
gfc_add_ss_to_loop (&loop, maskss);
+ gfc_add_ss_to_loop (&loop, arrayss);
/* Initialize the loop. */
gfc_conv_ss_startstride (&loop);
@@ -5412,8 +5481,16 @@ gfc_conv_intrinsic_findloc (gfc_se *se, gfc_expr *expr)
tmp = build3_v (COND_EXPR, tmp, found, build_empty_stmt (input_location));
if (maskss)
- tmp = build3_v (COND_EXPR, maskse.expr, tmp,
- build_empty_stmt (input_location));
+ {
+ /* We enclose the above in if (mask) {...}. If the mask is
+ an optional argument, generate IF (.NOT. PRESENT(MASK)
+ .OR. MASK(I)). */
+
+ tree ifmask;
+ ifmask = conv_mask_condition (&maskse, maskexpr, optional_mask);
+ tmp = build3_v (COND_EXPR, ifmask, tmp,
+ build_empty_stmt (input_location));
+ }
gfc_add_expr_to_block (&body, tmp);
gfc_add_block_to_block (&body, &arrayse.post);
@@ -5444,12 +5521,15 @@ gfc_conv_intrinsic_findloc (gfc_se *se, gfc_expr *expr)
/* For a scalar mask, enclose the loop in an if statement. */
if (maskexpr && maskss == NULL)
{
+ tree ifmask;
tree if_stmt;
+
gfc_init_se (&maskse, NULL);
gfc_conv_expr_val (&maskse, maskexpr);
gfc_init_block (&block);
gfc_add_expr_to_block (&block, maskse.expr);
- if_stmt = build3_v (COND_EXPR, maskse.expr, tmp,
+ ifmask = conv_mask_condition (&maskse, maskexpr, optional_mask);
+ if_stmt = build3_v (COND_EXPR, ifmask, tmp,
build_empty_stmt (input_location));
gfc_add_expr_to_block (&block, if_stmt);
tmp = gfc_finish_block (&block);
@@ -5576,6 +5656,7 @@ gfc_conv_intrinsic_minmaxval (gfc_se * se, gfc_expr * expr, enum tree_code op)
gfc_expr *arrayexpr;
gfc_expr *maskexpr;
int n;
+ bool optional_mask;
if (se->ss)
{
@@ -5665,6 +5746,9 @@ gfc_conv_intrinsic_minmaxval (gfc_se * se, gfc_expr * expr, enum tree_code op)
actual = actual->next->next;
gcc_assert (actual);
maskexpr = actual->expr;
+ optional_mask = maskexpr && maskexpr->expr_type == EXPR_VARIABLE
+ && maskexpr->symtree->n.sym->attr.dummy
+ && maskexpr->symtree->n.sym->attr.optional;
nonempty = NULL;
if (maskexpr && maskexpr->rank != 0)
{
@@ -5687,9 +5771,14 @@ gfc_conv_intrinsic_minmaxval (gfc_se * se, gfc_expr * expr, enum tree_code op)
/* Initialize the scalarizer. */
gfc_init_loopinfo (&loop);
- gfc_add_ss_to_loop (&loop, arrayss);
+
+ /* We add the mask first because the number of iterations is taken
+ from the last ss, and this breaks if an absent optional argument
+ is used for mask. */
+
if (maskss)
gfc_add_ss_to_loop (&loop, maskss);
+ gfc_add_ss_to_loop (&loop, arrayss);
/* Initialize the loop. */
gfc_conv_ss_startstride (&loop);
@@ -5832,9 +5921,15 @@ gfc_conv_intrinsic_minmaxval (gfc_se * se, gfc_expr * expr, enum tree_code op)
tmp = gfc_finish_block (&block);
if (maskss)
- /* We enclose the above in if (mask) {...}. */
- tmp = build3_v (COND_EXPR, maskse.expr, tmp,
- build_empty_stmt (input_location));
+ {
+ /* We enclose the above in if (mask) {...}. If the mask is an
+ optional argument, generate IF (.NOT. PRESENT(MASK)
+ .OR. MASK(I)). */
+ tree ifmask;
+ ifmask = conv_mask_condition (&maskse, maskexpr, optional_mask);
+ tmp = build3_v (COND_EXPR, ifmask, tmp,
+ build_empty_stmt (input_location));
+ }
gfc_add_expr_to_block (&body, tmp);
if (lab)
@@ -5891,8 +5986,13 @@ gfc_conv_intrinsic_minmaxval (gfc_se * se, gfc_expr * expr, enum tree_code op)
tmp = gfc_finish_block (&block);
if (maskss)
/* We enclose the above in if (mask) {...}. */
- tmp = build3_v (COND_EXPR, maskse.expr, tmp,
- build_empty_stmt (input_location));
+ {
+ tree ifmask;
+ ifmask = conv_mask_condition (&maskse, maskexpr, optional_mask);
+ tmp = build3_v (COND_EXPR, ifmask, tmp,
+ build_empty_stmt (input_location));
+ }
+
gfc_add_expr_to_block (&body, tmp);
/* Avoid initializing loopvar[0] again, it should be left where
it finished by the first loop. */
@@ -5920,6 +6020,7 @@ gfc_conv_intrinsic_minmaxval (gfc_se * se, gfc_expr * expr, enum tree_code op)
if (maskexpr && maskss == NULL)
{
tree else_stmt;
+ tree ifmask;
gfc_init_se (&maskse, NULL);
gfc_conv_expr_val (&maskse, maskexpr);
@@ -5932,7 +6033,9 @@ gfc_conv_intrinsic_minmaxval (gfc_se * se, gfc_expr * expr, enum tree_code op)
else_stmt = build2_v (MODIFY_EXPR, limit, huge_cst);
else
else_stmt = build_empty_stmt (input_location);
- tmp = build3_v (COND_EXPR, maskse.expr, tmp, else_stmt);
+
+ ifmask = conv_mask_condition (&maskse, maskexpr, optional_mask);
+ tmp = build3_v (COND_EXPR, ifmask, tmp, else_stmt);
gfc_add_expr_to_block (&block, tmp);
gfc_add_block_to_block (&se->pre, &block);
}
@@ -10177,7 +10280,8 @@ gfc_walk_intrinsic_libfunc (gfc_ss * ss, gfc_expr * expr)
bool
gfc_inline_intrinsic_function_p (gfc_expr *expr)
{
- gfc_actual_arglist *args;
+ gfc_actual_arglist *args, *dim_arg, *mask_arg;
+ gfc_expr *maskexpr;
if (!expr->value.function.isym)
return false;
@@ -10191,10 +10295,25 @@ gfc_inline_intrinsic_function_p (gfc_expr *expr)
return false;
args = expr->value.function.actual;
+ dim_arg = args->next;
+
/* We need to be able to subset the SUM argument at compile-time. */
- if (args->next->expr && args->next->expr->expr_type != EXPR_CONSTANT)
+ if (dim_arg->expr && dim_arg->expr->expr_type != EXPR_CONSTANT)
return false;
+ /* FIXME: If MASK is optional for a more than two-dimensional
+ argument, the scalarizer gets confused if the mask is
+ absent. See PR 82995. For now, fall back to the library
+ function. */
+
+ mask_arg = dim_arg->next;
+ maskexpr = mask_arg->expr;
+
+ if (expr->rank > 0 && maskexpr && maskexpr->expr_type == EXPR_VARIABLE
+ && maskexpr->symtree->n.sym->attr.dummy
+ && maskexpr->symtree->n.sym->attr.optional)
+ return false;
+
return true;
case GFC_ISYM_TRANSPOSE: