From 4be1cc5f50578fafcdcbd09160235066d76a3f86 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 10 Apr 2024 10:08:12 +0200 Subject: [PATCH] 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 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. --- gcc/cp/semantics.cc | 75 ++++++++- gcc/gimplify.cc | 1 + .../g++.dg/cpp26/trivial-infinite-loop1.C | 148 ++++++++++++++++++ .../g++.dg/cpp26/trivial-infinite-loop2.C | 147 +++++++++++++++++ .../g++.dg/cpp26/trivial-infinite-loop3.C | 148 ++++++++++++++++++ gcc/tree-cfg.cc | 10 +- gcc/tree-core.h | 1 + gcc/tree-pretty-print.cc | 3 + 8 files changed, 527 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop1.C create mode 100644 gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop2.C create mode 100644 gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop3.C diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 329c524a509..abaa4a3ca53 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -1090,7 +1090,8 @@ find_std_constant_evaluated_r (tree *tp, int *walk_subtrees, void *) (e.g., in a non-constexpr non-consteval function) so give the user a clue. */ static void -maybe_warn_for_constant_evaluated (tree cond, bool constexpr_if) +maybe_warn_for_constant_evaluated (tree cond, bool constexpr_if, + bool trivial_infinite) { if (!warn_tautological_compare) return; @@ -1108,6 +1109,18 @@ maybe_warn_for_constant_evaluated (tree cond, bool constexpr_if) warning_at (EXPR_LOCATION (cond), OPT_Wtautological_compare, "% always evaluates to " "true in %"); + else if (trivial_infinite) + { + auto_diagnostic_group d; + if (warning_at (EXPR_LOCATION (cond), OPT_Wtautological_compare, + "% evaluates to " + "true when checking if trivially empty iteration " + "statement is trivial infinite loop") + && !maybe_constexpr_fn (current_function_decl)) + inform (EXPR_LOCATION (cond), + "and evaluates to false when actually evaluating " + "the condition in non-% function"); + } else if (!maybe_constexpr_fn (current_function_decl)) warning_at (EXPR_LOCATION (cond), OPT_Wtautological_compare, "% always evaluates to " @@ -1126,7 +1139,8 @@ tree finish_if_stmt_cond (tree orig_cond, tree if_stmt) { tree cond = maybe_convert_cond (orig_cond); - maybe_warn_for_constant_evaluated (cond, IF_STMT_CONSTEXPR_P (if_stmt)); + maybe_warn_for_constant_evaluated (cond, IF_STMT_CONSTEXPR_P (if_stmt), + /*trivial_infinite=*/false); if (IF_STMT_CONSTEXPR_P (if_stmt) && !type_dependent_expression_p (cond) && require_constant_expression (cond) @@ -1205,6 +1219,48 @@ finish_if_stmt (tree if_stmt) add_stmt (do_poplevel (scope)); } +/* Determine if iteration statement with *CONDP condition and + loop BODY is trivially empty iteration statement or even + trivial infinite loop. In the latter case for -ffinite-loops + add ANNOTATE_EXPR to mark the loop as maybe validly infinite. + Also, emit -Wtautological-compare warning for std::is_constant_evaluated () + calls in the condition when needed. */ + +static void +finish_loop_cond (tree *condp, tree body) +{ + if (TREE_CODE (*condp) == INTEGER_CST) + return; + bool trivially_empty = expr_first (body) == NULL_TREE; + bool trivial_infinite = false; + if (trivially_empty) + { + tree c = fold_non_dependent_expr (*condp, tf_none, + /*manifestly_const_eval=*/true); + trivial_infinite = c && integer_nonzerop (c); + } + if (warn_tautological_compare) + { + tree cond = *condp; + while (TREE_CODE (cond) == ANNOTATE_EXPR) + cond = TREE_OPERAND (cond, 0); + if (trivial_infinite + && !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)) + maybe_warn_for_constant_evaluated (cond, /*constexpr_if=*/false, + /*trivial_infinite=*/true); + else if (!trivially_empty + || !processing_template_decl + || DECL_IMMEDIATE_FUNCTION_P (current_function_decl)) + maybe_warn_for_constant_evaluated (cond, /*constexpr_if=*/false, + /*trivial_infinite=*/false); + } + if (trivial_infinite && flag_finite_loops && !processing_template_decl) + *condp = build3 (ANNOTATE_EXPR, TREE_TYPE (*condp), *condp, + build_int_cst (integer_type_node, + annot_expr_maybe_infinite_kind), + integer_zero_node); +} + /* Begin a while-statement. Returns a newly created WHILE_STMT if appropriate. */ @@ -1260,6 +1316,7 @@ finish_while_stmt (tree while_stmt) { end_maybe_infinite_loop (boolean_true_node); WHILE_BODY (while_stmt) = do_poplevel (WHILE_BODY (while_stmt)); + finish_loop_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt)); } /* Begin a do-statement. Returns a newly created DO_STMT if @@ -1317,6 +1374,12 @@ finish_do_stmt (tree cond, tree do_stmt, bool ivdep, tree unroll, build_int_cst (integer_type_node, annot_expr_no_vector_kind), integer_zero_node); DO_COND (do_stmt) = cond; + tree do_body = DO_BODY (do_stmt); + if (CONVERT_EXPR_P (do_body) + && integer_zerop (TREE_OPERAND (do_body, 0)) + && VOID_TYPE_P (TREE_TYPE (do_body))) + do_body = NULL_TREE; + finish_loop_cond (&DO_COND (do_stmt), do_body); } /* Finish a return-statement. The EXPRESSION returned, if any, is as @@ -1487,7 +1550,13 @@ finish_for_stmt (tree for_stmt) if (TREE_CODE (for_stmt) == RANGE_FOR_STMT) RANGE_FOR_BODY (for_stmt) = do_poplevel (RANGE_FOR_BODY (for_stmt)); else - FOR_BODY (for_stmt) = do_poplevel (FOR_BODY (for_stmt)); + { + FOR_BODY (for_stmt) = do_poplevel (FOR_BODY (for_stmt)); + if (FOR_COND (for_stmt)) + finish_loop_cond (&FOR_COND (for_stmt), + FOR_EXPR (for_stmt) ? integer_one_node + : FOR_BODY (for_stmt)); + } /* Pop the scope for the body of the loop. */ tree *scope_ptr = (TREE_CODE (for_stmt) == RANGE_FOR_STMT diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 7b972c093ba..3b731525f15 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -4584,6 +4584,7 @@ gimple_boolify (tree expr) case annot_expr_no_vector_kind: case annot_expr_vector_kind: case annot_expr_parallel_kind: + case annot_expr_maybe_infinite_kind: TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0)); if (TREE_CODE (type) != BOOLEAN_TYPE) TREE_TYPE (expr) = boolean_type_node; diff --git a/gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop1.C b/gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop1.C new file mode 100644 index 00000000000..288a736e4de --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop1.C @@ -0,0 +1,148 @@ +// P2809R3 - Trivial infinite loops are not Undefined Behavior +// { dg-do compile { target c++11 } } +// { dg-additional-options "-fdump-tree-gimple -fno-inline -Wtautological-compare -O2" } +// { dg-final { scan-tree-dump-times ".ANNOTATE \\\(\[^\n\r]*, 5, 0\\\)" 32 "gimple" { target c++20 } } } +// { dg-final { scan-tree-dump-times ".ANNOTATE \\\(\[^\n\r]*, 5, 0\\\)" 16 "gimple" { target c++17_down } } } + +volatile int v; + +constexpr bool +foo () +{ + return true; +} + +struct S +{ + constexpr S () : s (true) {} + constexpr operator bool () const { return s; } + bool s; +}; + +#if __cplusplus >= 202002L +namespace std { + constexpr inline bool + is_constant_evaluated () noexcept + { +#if __cpp_if_consteval >= 202106L + if consteval { return true; } else { return false; } +#else + return __builtin_is_constant_evaluated (); +#endif + } +} + +constexpr bool +baz () +{ + return std::is_constant_evaluated (); +} +#endif + +void +bar (int x) +{ + switch (x) + { + case 0: + while (foo ()) ; + break; + case 1: + while (foo ()) {} + break; + case 2: + do ; while (foo ()); + break; + case 3: + do {} while (foo ()); + break; + case 4: + for (v = 42; foo (); ) ; + break; + case 5: + for (v = 42; foo (); ) {} + break; + case 6: + for (int w = 42; foo (); ) ; + break; + case 7: + for (int w = 42; foo (); ) {} + break; + case 10: + while (S {}) ; + break; + case 11: + while (S {}) {} + break; + case 12: + do ; while (S {}); + break; + case 13: + do {} while (S {}); + break; + case 14: + for (v = 42; S {}; ) ; + break; + case 15: + for (v = 42; S {}; ) {} + break; + case 16: + for (int w = 42; S {}; ) ; + break; + case 17: + for (int w = 42; S {}; ) {} + break; +#if __cplusplus >= 202002L + case 20: + while (baz ()) ; + break; + case 21: + while (baz ()) {} + break; + case 22: + do ; while (baz ()); + break; + case 23: + do {} while (baz ()); + break; + case 24: + for (v = 42; baz (); ) ; + break; + case 25: + for (v = 42; baz (); ) {} + break; + case 26: + for (int w = 42; baz (); ) ; + break; + case 27: + for (int w = 42; baz (); ) {} + break; + case 30: + while (std::is_constant_evaluated ()) ; // { dg-warning "'std::is_constant_evaluated' evaluates to true when checking if trivially empty iteration statement is trivial infinite loop" "" { target c++20 } } + break; // { dg-message "and evaluates to false when actually evaluating the condition in non-'constexpr' function" "" { target c++20 } .-1 } + case 31: + while (std::is_constant_evaluated ()) {} // { dg-warning "'std::is_constant_evaluated' evaluates to true when checking if trivially empty iteration statement is trivial infinite loop" "" { target c++20 } } + break; // { dg-message "and evaluates to false when actually evaluating the condition in non-'constexpr' function" "" { target c++20 } .-1 } + case 32: + do ; while (std::is_constant_evaluated ()); // { dg-warning "'std::is_constant_evaluated' evaluates to true when checking if trivially empty iteration statement is trivial infinite loop" "" { target c++20 } } + break; // { dg-message "and evaluates to false when actually evaluating the condition in non-'constexpr' function" "" { target c++20 } .-1 } + case 33: + do {} while (std::is_constant_evaluated ()); // { dg-warning "'std::is_constant_evaluated' evaluates to true when checking if trivially empty iteration statement is trivial infinite loop" "" { target c++20 } } + break; // { dg-message "and evaluates to false when actually evaluating the condition in non-'constexpr' function" "" { target c++20 } .-1 } + case 34: + for (v = 42; std::is_constant_evaluated (); ) ; // { dg-warning "'std::is_constant_evaluated' evaluates to true when checking if trivially empty iteration statement is trivial infinite loop" "" { target c++20 } } + break; // { dg-message "and evaluates to false when actually evaluating the condition in non-'constexpr' function" "" { target c++20 } .-1 } + case 35: + for (v = 42; std::is_constant_evaluated (); ) {} // { dg-warning "'std::is_constant_evaluated' evaluates to true when checking if trivially empty iteration statement is trivial infinite loop" "" { target c++20 } } + break; // { dg-message "and evaluates to false when actually evaluating the condition in non-'constexpr' function" "" { target c++20 } .-1 } + case 36: + for (int w = 42; std::is_constant_evaluated (); ) ; // { dg-warning "'std::is_constant_evaluated' evaluates to true when checking if trivially empty iteration statement is trivial infinite loop" "" { target c++20 } } + break; // { dg-message "and evaluates to false when actually evaluating the condition in non-'constexpr' function" "" { target c++20 } .-1 } + case 37: + for (int w = 42; std::is_constant_evaluated (); ) {} // { dg-warning "'std::is_constant_evaluated' evaluates to true when checking if trivially empty iteration statement is trivial infinite loop" "" { target c++20 } } + break; // { dg-message "and evaluates to false when actually evaluating the condition in non-'constexpr' function" "" { target c++20 } .-1 } +#endif + default: + break; + } +} diff --git a/gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop2.C b/gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop2.C new file mode 100644 index 00000000000..fd8305e7f8a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop2.C @@ -0,0 +1,147 @@ +// P2809R3 - Trivial infinite loops are not Undefined Behavior +// { dg-do compile { target c++11 } } +// { dg-additional-options "-fdump-tree-gimple -fno-inline -Wtautological-compare -O2" } +// { dg-final { scan-tree-dump-not ".ANNOTATE \\\(\[^\n\r]*, 5, 0\\\)" "gimple" } } + +volatile int v; + +constexpr bool +foo () +{ + return false; +} + +struct S +{ + constexpr S () : s (false) {} + constexpr operator bool () const { return s; } + bool s; +}; + +#if __cplusplus >= 202002L +namespace std { + constexpr inline bool + is_constant_evaluated () noexcept + { +#if __cpp_if_consteval >= 202106L + if consteval { return true; } else { return false; } +#else + return __builtin_is_constant_evaluated (); +#endif + } +} + +constexpr bool +baz () +{ + return !std::is_constant_evaluated (); +} +#endif + +void +bar (int x) +{ + switch (x) + { + case 0: + while (foo ()) ; + break; + case 1: + while (foo ()) {} + break; + case 2: + do ; while (foo ()); + break; + case 3: + do {} while (foo ()); + break; + case 4: + for (v = 42; foo (); ) ; + break; + case 5: + for (v = 42; foo (); ) {} + break; + case 6: + for (int w = 42; foo (); ) ; + break; + case 7: + for (int w = 42; foo (); ) {} + break; + case 10: + while (S {}) ; + break; + case 11: + while (S {}) {} + break; + case 12: + do ; while (S {}); + break; + case 13: + do {} while (S {}); + break; + case 14: + for (v = 42; S {}; ) ; + break; + case 15: + for (v = 42; S {}; ) {} + break; + case 16: + for (int w = 42; S {}; ) ; + break; + case 17: + for (int w = 42; S {}; ) {} + break; +#if __cplusplus >= 202002L + case 20: + while (baz ()) ; + break; + case 21: + while (baz ()) {} + break; + case 22: + do ; while (baz ()); + break; + case 23: + do {} while (baz ()); + break; + case 24: + for (v = 42; baz (); ) ; + break; + case 25: + for (v = 42; baz (); ) {} + break; + case 26: + for (int w = 42; baz (); ) ; + break; + case 27: + for (int w = 42; baz (); ) {} + break; + case 30: + while (!std::is_constant_evaluated ()) ; // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 31: + while (!std::is_constant_evaluated ()) {} // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 32: + do ; while (!std::is_constant_evaluated ()); // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 33: + do {} while (!std::is_constant_evaluated ()); // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 34: + for (v = 42; !std::is_constant_evaluated (); ) ; // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 35: + for (v = 42; !std::is_constant_evaluated (); ) {} // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 36: + for (int w = 42; !std::is_constant_evaluated (); ) ; // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 37: + for (int w = 42; !std::is_constant_evaluated (); ) {} // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; +#endif + default: + break; + } +} diff --git a/gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop3.C b/gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop3.C new file mode 100644 index 00000000000..e88d55317be --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop3.C @@ -0,0 +1,148 @@ +// P2809R3 - Trivial infinite loops are not Undefined Behavior +// { dg-do compile { target c++11 } } +// { dg-additional-options "-fdump-tree-gimple -fno-inline -Wtautological-compare" } +// { dg-final { scan-tree-dump-not ".ANNOTATE \\\(\[^\n\r]*, 5, 0\\\)" "gimple" } } + +volatile int v; +int y; + +constexpr bool +foo () +{ + return true; +} + +struct S +{ + constexpr S () : s (true) {} + constexpr operator bool () const { return s; } + bool s; +}; + +#if __cplusplus >= 202002L +namespace std { + constexpr inline bool + is_constant_evaluated () noexcept + { +#if __cpp_if_consteval >= 202106L + if consteval { return true; } else { return false; } +#else + return __builtin_is_constant_evaluated (); +#endif + } +} + +constexpr bool +baz () +{ + return std::is_constant_evaluated (); +} +#endif + +void +bar (int x) +{ + switch (x) + { + case 0: + while (foo ()) ++y; + break; + case 1: + while (foo ()) { ++y; } + break; + case 2: + do ++y; while (foo ()); + break; + case 3: + do { ++y; } while (foo ()); + break; + case 4: + for (v = 42; foo (); ) ++y; + break; + case 5: + for (v = 42; foo (); ) { ++y; } + break; + case 6: + for (int w = 42; foo (); ) ++y; + break; + case 7: + for (int w = 42; foo (); ) { ++y; } + break; + case 10: + while (S {}) ++y; + break; + case 11: + while (S {}) { ++y; } + break; + case 12: + do ++y; while (S {}); + break; + case 13: + do { ++y; } while (S {}); + break; + case 14: + for (v = 42; S {}; ) ++y; + break; + case 15: + for (v = 42; S {}; ) { ++y; } + break; + case 16: + for (int w = 42; S {}; ) ++y; + break; + case 17: + for (int w = 42; S {}; ) { ++y; } + break; +#if __cplusplus >= 202002L + case 20: + while (baz ()) ++y; + break; + case 21: + while (baz ()) { ++y; } + break; + case 22: + do ++y; while (baz ()); + break; + case 23: + do { ++y; } while (baz ()); + break; + case 24: + for (v = 42; baz (); ) ++y; + break; + case 25: + for (v = 42; baz (); ) { ++y; } + break; + case 26: + for (int w = 42; baz (); ) ++y; + break; + case 27: + for (int w = 42; baz (); ) { ++y; } + break; + case 30: + while (std::is_constant_evaluated ()) ++y; // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 31: + while (std::is_constant_evaluated ()) { ++y; } // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 32: + do ++y; while (std::is_constant_evaluated ()); // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 33: + do { ++y; } while (std::is_constant_evaluated ()); // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 34: + for (v = 42; std::is_constant_evaluated (); ) ++y; // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 35: + for (v = 42; std::is_constant_evaluated (); ) { ++y; } // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 36: + for (int w = 42; std::is_constant_evaluated (); ) ++y; // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; + case 37: + for (int w = 42; std::is_constant_evaluated (); ) { ++y; } // { dg-warning "'std::is_constant_evaluated' always evaluates to false in a non-'constexpr' function" "" { target c++20 } } + break; +#endif + default: + break; + } +} diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index bdffc3b4ed2..96686db8ed3 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 (); diff --git a/gcc/tree-core.h b/gcc/tree-core.h index a8439f8acbb..9fa74342919 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -983,6 +983,7 @@ enum annot_expr_kind { annot_expr_no_vector_kind, annot_expr_vector_kind, annot_expr_parallel_kind, + annot_expr_maybe_infinite_kind, annot_expr_kind_last }; diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc index 926f7e006a7..c935a7da7d1 100644 --- a/gcc/tree-pretty-print.cc +++ b/gcc/tree-pretty-print.cc @@ -3479,6 +3479,9 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, case annot_expr_parallel_kind: pp_string (pp, ", parallel"); break; + case annot_expr_maybe_infinite_kind: + pp_string (pp, ", maybe-infinite"); + break; default: gcc_unreachable (); }