diff options
author | Jakub Jelinek <jakub@redhat.com> | 2024-04-10 10:08:12 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2024-04-10 10:19:04 +0200 |
commit | 4be1cc5f50578fafcdcbd09160235066d76a3f86 (patch) | |
tree | a763e327dd8ec081d05b7299de58c38efd149b00 /gcc/tree-cfg.cc | |
parent | 4923ed49b93352bcf9e43cafac38345e4a54c3f8 (diff) | |
download | gcc-4be1cc5f50578fafcdcbd09160235066d76a3f86.zip gcc-4be1cc5f50578fafcdcbd09160235066d76a3f86.tar.gz gcc-4be1cc5f50578fafcdcbd09160235066d76a3f86.tar.bz2 |
c++: Implement C++26 P2809R3 - Trivial infinite loops are not Undefined Behavior
The following patch attempts to implement P2809R3, which has been voted
in as a DR.
The middle-end has its behavior documented:
'-ffinite-loops'
Assume that a loop with an exit will eventually take the exit and
not loop indefinitely. This allows the compiler to remove loops
that otherwise have no side-effects, not considering eventual
endless looping as such.
This option is enabled by default at '-O2' for C++ with -std=c++11
or higher.
So, the following patch attempts to detect trivial infinite loops by detecting
trivially empty loops, if their condition is not INTEGER_CST (that case is
handled by the middle-end right already) trying to constant evaluate with
mce=true their condition and if it evaluates to true (and -ffinite-loops and
not processing_template_decl) wraps the condition into an ANNOTATE_EXPR which
tells the middle-end that the loop shouldn't be loop->finite_p despite
-ffinite-loops).
Furthermore, the patch adds -Wtautological-compare warnings for loop
conditions containing std::is_constant_evaluated(), either if those
always evaluate to true, or always evaluate to false, or will evaluate
to true just when checking if it is trivial infinite loop (and if in non-constexpr
function also say that it will evaluate to false otherwise).
The user is doing something weird in all those cases.
2024-04-10 Jakub Jelinek <jakub@redhat.com>
PR c++/114462
gcc/
* tree-core.h (enum annot_expr_kind): Add
annot_expr_maybe_infinite_kind enumerator.
* gimplify.cc (gimple_boolify): Handle annot_expr_maybe_infinite_kind.
* tree-cfg.cc (replace_loop_annotate_in_block): Likewise.
(replace_loop_annotate): Likewise. Move loop->finite_p initialization
before the replace_loop_annotate_in_block calls.
* tree-pretty-print.cc (dump_generic_node): Handle
annot_expr_maybe_infinite_kind.
gcc/cp/
* semantics.cc: Implement C++26 P2809R3 - Trivial infinite
loops are not Undefined Behavior.
(maybe_warn_for_constant_evaluated): Add trivial_infinite argument
and emit special diagnostics for that case.
(finish_if_stmt_cond): Adjust caller.
(finish_loop_cond): New function.
(finish_while_stmt): Use it.
(finish_do_stmt): Likewise.
(finish_for_stmt): Likewise.
gcc/testsuite/
* g++.dg/cpp26/trivial-infinite-loop1.C: New test.
* g++.dg/cpp26/trivial-infinite-loop2.C: New test.
* g++.dg/cpp26/trivial-infinite-loop3.C: New test.
Diffstat (limited to 'gcc/tree-cfg.cc')
-rw-r--r-- | gcc/tree-cfg.cc | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index bdffc3b..96686db 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -297,6 +297,9 @@ replace_loop_annotate_in_block (basic_block bb, class loop *loop) loop->can_be_parallel = true; loop->safelen = INT_MAX; break; + case annot_expr_maybe_infinite_kind: + loop->finite_p = false; + break; default: gcc_unreachable (); } @@ -320,12 +323,12 @@ replace_loop_annotate (void) for (auto loop : loops_list (cfun, 0)) { + /* Push the global flag_finite_loops state down to individual loops. */ + loop->finite_p = flag_finite_loops; + /* Check all exit source blocks for annotations. */ for (auto e : get_loop_exit_edges (loop)) replace_loop_annotate_in_block (e->src, loop); - - /* Push the global flag_finite_loops state down to individual loops. */ - loop->finite_p = flag_finite_loops; } /* Remove IFN_ANNOTATE. Safeguard for the case loop->latch == NULL. */ @@ -347,6 +350,7 @@ replace_loop_annotate (void) case annot_expr_no_vector_kind: case annot_expr_vector_kind: case annot_expr_parallel_kind: + case annot_expr_maybe_infinite_kind: break; default: gcc_unreachable (); |