+2018-07-18 Janus Weil <janus@gcc.gnu.org>
+ Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/85599
+ * dump-parse-tree.c (show_attr): Add handling of implicit_pure.
+ * frontend-passes.c (do_warn_function_elimination): Do not warn for
+ pure functions.
+ * gfortran.h: Add prototypes for gfc_pure_function and
+ gfc_implicit_pure_function.
+ * gfortran.texi: Add chapter on evaluation of logical expressions.
+ * invoke.texi: Mention that -Wfunction-elimination is implied
+ by -Wextra.
+ * lang.opt: Make -Wextra imply -Wfunction-elimination.
+ * resolve.c (pure_function): Rename to gfc_pure_function.
+ (gfc_implicit_pure_function): New function.
+ (check_pure_function): Use it here.
+ (impure_function_callback): New function.
+ (resolve_operator): Call it via gfc_expr_walker.
+
2018-07-16 Fritz Reese <fritzoreese@gmail.com>
PR fortran/83184
fputs (" ELEMENTAL", dumpfile);
if (attr->pure)
fputs (" PURE", dumpfile);
+ if (attr->implicit_pure)
+ fputs (" IMPLICIT_PURE", dumpfile);
if (attr->recursive)
fputs (" RECURSIVE", dumpfile);
static void
do_warn_function_elimination (gfc_expr *e)
{
- if (e->expr_type != EXPR_FUNCTION)
- return;
- if (e->value.function.esym)
- gfc_warning (OPT_Wfunction_elimination,
- "Removing call to function %qs at %L",
- e->value.function.esym->name, &(e->where));
- else if (e->value.function.isym)
- gfc_warning (OPT_Wfunction_elimination,
- "Removing call to function %qs at %L",
- e->value.function.isym->name, &(e->where));
+ const char *name;
+ if (e->expr_type == EXPR_FUNCTION
+ && !gfc_pure_function (e, &name) && !gfc_implicit_pure_function (e))
+ {
+ if (name)
+ gfc_warning (OPT_Wfunction_elimination,
+ "Removing call to impure function %qs at %L", name,
+ &(e->where));
+ else
+ gfc_warning (OPT_Wfunction_elimination,
+ "Removing call to impure function at %L",
+ &(e->where));
+ }
}
+
+
/* Callback function for the code walker for doing common function
elimination. This builds up the list of functions in the expression
and goes through them to detect duplicates, which it then replaces
bool gfc_explicit_interface_required (gfc_symbol *, char *, int);
extern int gfc_do_concurrent_flag;
const char* gfc_lookup_function_fuzzy (const char *, gfc_symtree *);
+int gfc_pure_function (gfc_expr *e, const char **name);
+int gfc_implicit_pure_function (gfc_expr *e);
/* array.c */
@menu
* KIND Type Parameters::
* Internal representation of LOGICAL variables::
+* Evaluation of logical expressions::
* Thread-safety of the runtime library::
* Data consistency and durability::
* Files opened without an explicit ACTION= specifier::
See also @ref{Argument passing conventions} and @ref{Interoperability with C}.
+@node Evaluation of logical expressions
+@section Evaluation of logical expressions
+
+The Fortran standard does not require the compiler to evaluate all parts of an
+expression, if they do not contribute to the final result. For logical
+expressions with @code{.AND.} or @code{.OR.} operators, in particular, GNU
+Fortran will optimize out function calls (even to impure functions) if the
+result of the expression can be established without them. However, since not
+all compilers do that, and such an optimization can potentially modify the
+program flow and subsequent results, GNU Fortran throws warnings for such
+situations with the @option{-Wfunction-elimination} flag.
+
+
@node Thread-safety of the runtime library
@section Thread-safety of the runtime library
@cindex thread-safety, threads
@opindex @code{Wfunction-elimination}
@cindex function elimination
@cindex warnings, function elimination
-Warn if any calls to functions are eliminated by the optimizations
+Warn if any calls to impure functions are eliminated by the optimizations
enabled by the @option{-ffrontend-optimize} option.
+This option is implied by @option{-Wextra}.
@item -Wrealloc-lhs
@opindex @code{Wrealloc-lhs}
Warn if loops have been interchanged.
Wfunction-elimination
-Fortran Warning Var(warn_function_elimination)
+Fortran Warning Var(warn_function_elimination) LangEnabledBy(Fortran,Wextra)
Warn about function call elimination.
Wimplicit-interface
static int
pure_stmt_function (gfc_expr *, gfc_symbol *);
-static int
-pure_function (gfc_expr *e, const char **name)
+int
+gfc_pure_function (gfc_expr *e, const char **name)
{
int pure;
gfc_component *comp;
}
+/* Check if the expression is a reference to an implicitly pure function. */
+
+int
+gfc_implicit_pure_function (gfc_expr *e)
+{
+ gfc_component *comp = gfc_get_proc_ptr_comp (e);
+ if (comp)
+ return gfc_implicit_pure (comp->ts.interface);
+ else if (e->value.function.esym)
+ return gfc_implicit_pure (e->value.function.esym);
+ else
+ return 0;
+}
+
+
static bool
impure_stmt_fcn (gfc_expr *e, gfc_symbol *sym,
int *f ATTRIBUTE_UNUSED)
|| e->symtree->n.sym->attr.proc == PROC_ST_FUNCTION)
return false;
- return pure_function (e, &name) ? false : true;
+ return gfc_pure_function (e, &name) ? false : true;
}
static bool check_pure_function (gfc_expr *e)
{
const char *name = NULL;
- if (!pure_function (e, &name) && name)
+ if (!gfc_pure_function (e, &name) && name)
{
if (forall_flag)
{
"within a PURE procedure", name, &e->where);
return false;
}
- gfc_unset_implicit_pure (NULL);
+ if (!gfc_implicit_pure_function (e))
+ gfc_unset_implicit_pure (NULL);
}
return true;
}
}
+/* Callback finding an impure function as an operand to an .and. or
+ .or. expression. Remember the last function warned about to
+ avoid double warnings when recursing. */
+
+static int
+impure_function_callback (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
+ void *data)
+{
+ gfc_expr *f = *e;
+ const char *name;
+ static gfc_expr *last = NULL;
+ bool *found = (bool *) data;
+
+ if (f->expr_type == EXPR_FUNCTION)
+ {
+ *found = 1;
+ if (f != last && !gfc_pure_function (f, &name)
+ && !gfc_implicit_pure_function (f))
+ {
+ if (name)
+ gfc_warning (OPT_Wfunction_elimination,
+ "Impure function %qs at %L might not be evaluated",
+ name, &f->where);
+ else
+ gfc_warning (OPT_Wfunction_elimination,
+ "Impure function at %L might not be evaluated",
+ &f->where);
+ }
+ last = f;
+ }
+
+ return 0;
+}
+
+
/* Resolve an operator expression node. This can involve replacing the
operation with a user defined function call. */
gfc_convert_type (op1, &e->ts, 2);
else if (op2->ts.kind < e->ts.kind)
gfc_convert_type (op2, &e->ts, 2);
+
+ if (e->value.op.op == INTRINSIC_AND || e->value.op.op == INTRINSIC_OR)
+ {
+ /* Warn about short-circuiting
+ with impure function as second operand. */
+ bool op2_f = false;
+ gfc_expr_walker (&op2, impure_function_callback, &op2_f);
+ }
break;
}
+2018-07-18 Janus Weil <janus@gcc.gnu.org>
+
+ PR fortran/85599
+ * gfortran.dg/function_optimize_5.f90: Add option
+ '-faggressive-function-elimination' and update dg-warning clauses.
+ * gfortran.dg/short_circuiting.f90: New test.
+
2018-07-18 Marek Polacek <polacek@redhat.com>
PR c++/86190 - bogus -Wsign-conversion warning
! { dg-do compile }
-! { dg-options "-ffrontend-optimize -finline-matmul-limit=0 -Wfunction-elimination" }
+! { dg-options "-ffrontend-optimize -faggressive-function-elimination -finline-matmul-limit=0 -Wfunction-elimination" }
! Check the -ffrontend-optimize (in the absence of -O) and
! -Wfunction-elimination options.
program main
data a /2., 3., 5., 7./
data b /11., 13., 17., 23./
- write (unit=line, fmt='(4F7.2)') matmul(a,b) & ! { dg-warning "Removing call to function 'matmul'" }
+ write (unit=line, fmt='(4F7.2)') matmul(a,b) &
& + matmul(a,b)
- z = sin(x) + 2.0 + sin(x) ! { dg-warning "Removing call to function 'sin'" }
+ z = sin(x) + 2.0 + sin(x)
print *,z
- x = ext_func(a) + 23 + ext_func(a)
+ x = ext_func(a) + 23 + ext_func(a) ! { dg-warning "Removing call to impure function" }
print *,d,x
- z = element(x) + element(x) ! { dg-warning "Removing call to function 'element'" }
+ z = element(x) + element(x)
print *,z
- i = mypure(x) - mypure(x) ! { dg-warning "Removing call to function 'mypure'" }
+ i = mypure(x) - mypure(x)
print *,i
- z = elem_impure(x) - elem_impure(x)
+ z = elem_impure(x) - elem_impure(x) ! { dg-warning "Removing call to impure function" }
print *,z
end program main
--- /dev/null
+! { dg-do compile }
+! { dg-additional-options "-Wextra" }
+!
+! PR 85599: warn about short-circuiting of logical expressions for non-pure functions
+!
+! Contributed by Janus Weil <janus@gcc.gnu.org>
+
+module a
+
+ interface impl_pure_a
+ module procedure impl_pure_a1
+ end interface
+
+contains
+
+ logical function impl_pure_a1()
+ impl_pure_a1 = .true.
+ end function
+
+end module
+
+
+program short_circuit
+
+ use a
+
+ logical :: flag
+ flag = .false.
+ flag = check() .and. flag
+ flag = flag .and. check() ! { dg-warning "might not be evaluated" }
+ flag = flag .and. pure_check()
+ flag = flag .and. impl_pure_1()
+ flag = flag .and. impl_pure_2()
+ flag = flag .and. impl_pure_a1()
+ flag = flag .and. impl_pure_a()
+
+contains
+
+ logical function check()
+ integer, save :: i = 1
+ print *, "check", i
+ i = i + 1
+ check = .true.
+ end function
+
+ logical pure function pure_check()
+ pure_check = .true.
+ end function
+
+ logical function impl_pure_1()
+ impl_pure_1 = .true.
+ end function
+
+ logical function impl_pure_2()
+ impl_pure_2 = impl_pure_1()
+ end function
+
+
+end