public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Jakub Jelinek <jakub@redhat.com>
To: Jason Merrill <jason@redhat.com>
Cc: gcc-patches@gcc.gnu.org
Subject: [PATCH] c++, v2: Implement C++26 P2809R3 - Trivial infinite loops are not Undefined Behavior
Date: Fri, 5 Apr 2024 09:57:03 +0200	[thread overview]
Message-ID: <Zg+uz0I1M3FQRuZ+@tucnak> (raw)

Hi!

Here is a new version of the PR114462 P2809R3 patch.
As clarified on core, for trivially empty iteration statements
(where the condition isn't empty or INTEGER_CST, because those
loops can't contain std::is_constant_evaluated() in the condition
and the middle-end handles them right even with -ffinite-loops)
it attempts to fold_non_dependent_expr with manifestly_const_eval=true
the expression and if that returns integer_nonzerop, treats it
as trivial infinite loops, but keeps the condition as is.
Instead for -ffinite-loops it adds ANNOTATE_EXPR that the loop is
maybe infinite to override -ffinite-loops behavior for the particular loop.

And, it also emits maybe_warn_for_constant_evaluated warnings for loop
conditions.  For non-trivially empty loops or in immediate functions
or if !processing_template_decl and the condition of trivially empty loops
is not a constant expression or doesn't evaluate to integer non-zero
warns like for condition of non-constexpr if, and in non-constexpr functions
when the condition constant evaluates to true warns that the code has
weird behavior, that it evaluates to true when checking if the loop
is trivially infinite and to false at runtime.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2024-04-05  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.

--- gcc/tree-core.h.jj	2024-03-15 09:13:35.333541416 +0100
+++ gcc/tree-core.h	2024-04-04 12:39:42.707652592 +0200
@@ -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
 };
 
--- gcc/gimplify.cc.jj	2024-03-11 12:36:18.494005912 +0100
+++ gcc/gimplify.cc	2024-04-04 12:40:44.619799465 +0200
@@ -4516,6 +4516,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;
--- gcc/tree-cfg.cc.jj	2024-02-15 09:51:34.608063945 +0100
+++ gcc/tree-cfg.cc	2024-04-04 12:42:38.271233376 +0200
@@ -297,6 +297,9 @@ replace_loop_annotate_in_block (basic_bl
 	  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 ();
--- gcc/tree-pretty-print.cc.jj	2024-03-14 14:07:34.303423928 +0100
+++ gcc/tree-pretty-print.cc	2024-04-04 12:39:35.369753709 +0200
@@ -3479,6 +3479,9 @@ dump_generic_node (pretty_printer *pp, t
 	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 ();
 	}
--- gcc/cp/semantics.cc.jj	2024-04-04 12:11:36.203886572 +0200
+++ gcc/cp/semantics.cc	2024-04-04 14:45:36.641830281 +0200
@@ -1090,7 +1090,8 @@ find_std_constant_evaluated_r (tree *tp,
    (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,17 @@ maybe_warn_for_constant_evaluated (tree
 	warning_at (EXPR_LOCATION (cond), OPT_Wtautological_compare,
 		    "%<std::is_constant_evaluated%> always evaluates to "
 		    "true in %<if constexpr%>");
+      else if (trivial_infinite)
+	{
+	  auto_diagnostic_group d;
+	  if (warning_at (EXPR_LOCATION (cond), OPT_Wtautological_compare,
+			  "%<std::is_constant_evaluated%> evaluates to "
+			  "true when checking if trivially empty iteration "
+			  "statement is trivial infinite loop"))
+	    inform (EXPR_LOCATION (cond),
+		    "and evaluates to false when actually evaluating "
+		    "the condition in non-%<constexpr%> function");
+	}
       else if (!maybe_constexpr_fn (current_function_decl))
 	warning_at (EXPR_LOCATION (cond), OPT_Wtautological_compare,
 		    "%<std::is_constant_evaluated%> always evaluates to "
@@ -1128,7 +1140,8 @@ finish_if_stmt_cond (tree orig_cond, tre
   tree cond = maybe_convert_cond (orig_cond);
   maybe_warn_for_constant_evaluated (cond,
 				     /*constexpr_if=*/
-				     IF_STMT_CONSTEXPR_P (if_stmt));
+				     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)
@@ -1207,6 +1220,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
+	  && !maybe_constexpr_fn (current_function_decl))
+	maybe_warn_for_constant_evaluated (cond, /*constexpr_if=*/false,
+					   /*trivial_infinite=*/true);
+      else if (!trivially_empty
+	       || (!processing_template_decl && !trivial_infinite)
+	       || 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.  */
 
@@ -1262,6 +1317,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
@@ -1319,6 +1375,12 @@ finish_do_stmt (tree cond, tree do_stmt,
 		   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
@@ -1489,7 +1551,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
--- gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop1.C.jj	2024-04-04 14:09:17.620753147 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop1.C	2024-04-04 14:35:54.951824609 +0200
@@ -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;
+    }
+}
--- gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop2.C.jj	2024-04-04 14:09:17.620753147 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop2.C	2024-04-04 14:36:38.936220130 +0200
@@ -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;
+    }
+}
--- gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop3.C.jj	2024-04-04 14:09:17.620753147 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop3.C	2024-04-04 14:37:37.870410190 +0200
@@ -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;
+    }
+}

	Jakub


             reply	other threads:[~2024-04-05  7:57 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-05  7:57 Jakub Jelinek [this message]
2024-04-08 22:53 ` Jason Merrill
2024-04-09  9:57   ` [PATCH] c++, v3: " Jakub Jelinek
2024-04-09 14:41     ` Jason Merrill

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Zg+uz0I1M3FQRuZ+@tucnak \
    --to=jakub@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jason@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).