Index: gcc/fortran/dump-parse-tree.c =================================================================== --- gcc/fortran/dump-parse-tree.c (revision 262563) +++ gcc/fortran/dump-parse-tree.c (working copy) @@ -716,6 +716,8 @@ show_attr (symbol_attribute *attr, const char * mo fputs (" ELEMENTAL", dumpfile); if (attr->pure) fputs (" PURE", dumpfile); + if (attr->implicit_pure) + fputs (" IMPLICIT_PURE", dumpfile); if (attr->recursive) fputs (" RECURSIVE", dumpfile); Index: gcc/fortran/gfortran.texi =================================================================== --- gcc/fortran/gfortran.texi (revision 262563) +++ gcc/fortran/gfortran.texi (working copy) @@ -1177,6 +1177,7 @@ might in some way or another become visible to the @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:: @@ -1251,6 +1252,19 @@ values: @code{1} for @code{.TRUE.} and @code{0} fo 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 Index: gcc/fortran/invoke.texi =================================================================== --- gcc/fortran/invoke.texi (revision 262563) +++ gcc/fortran/invoke.texi (working copy) @@ -1058,6 +1058,7 @@ off via @option{-Wno-align-commons}. See also @opt @cindex warnings, function elimination Warn if any calls to 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} Index: gcc/fortran/lang.opt =================================================================== --- gcc/fortran/lang.opt (revision 262563) +++ gcc/fortran/lang.opt (working copy) @@ -250,7 +250,7 @@ Fortran Var(flag_warn_frontend_loop_interchange) 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 Index: gcc/fortran/resolve.c =================================================================== --- gcc/fortran/resolve.c (revision 262563) +++ gcc/fortran/resolve.c (working copy) @@ -2982,6 +2982,21 @@ pure_function (gfc_expr *e, const char **name) } +/* Check if the expression is a reference to an implicitly pure function. */ + +static int +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) @@ -3034,7 +3049,8 @@ static bool check_pure_function (gfc_expr *e) "within a PURE procedure", name, &e->where); return false; } - gfc_unset_implicit_pure (NULL); + if (!implicit_pure_function (e)) + gfc_unset_implicit_pure (NULL); } return true; } @@ -3822,6 +3838,40 @@ lookup_uop_fuzzy (const char *op, gfc_symtree *uop } +/* 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 && !pure_function (f, &name) && !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. */ @@ -3930,6 +3980,14 @@ resolve_operator (gfc_expr *e) 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; }