[clang] [Clang] Implement P2809: Trivial infinite loops are not Undefined Behavior (PR #90066)

Hubert Tong via cfe-commits cfe-commits at lists.llvm.org
Sun May 5 19:20:53 PDT 2024


================
@@ -908,6 +908,69 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
     incrementProfileCounter(&S);
 }
 
+bool CodeGenFunction::checkIfLoopMustProgress(const Expr *ControllingExpression,
+                                              bool HasEmptyBody) {
+  if (CGM.getCodeGenOpts().getFiniteLoops() ==
+      CodeGenOptions::FiniteLoopsKind::Never)
+    return false;
+
+  // Now apply rules for plain C (see  6.8.5.6 in C11).
+  // Loops with constant conditions do not have to make progress in any C
+  // version.
+  // As an extension, we consisider loops whose constant expression
+  // can be constant-folded.
+  Expr::EvalResult Result;
+  bool CondIsConstInt =
----------------
hubert-reinterpretcast wrote:

> So... we treat it as a manifestly constant-evaluated for the purpose of checking whether the loop is trivial, but then flips to not manifestly constant-evaluated for the actual evaluation at runtime?

Yes.

> The wording could use some clarification...

The absence of wording to change the condition itself (that is, what is used at runtime) to be manifestly constant-evaluated is intentional. This wording is not unique. It is also used for the _determination_ of constant initialization, which #89565 (that you referred to) points out is also broken in Clang (however, in contrast to the condition case, once determined to be constant initialization, the initializer itself is considered manifestly constant-evaluated).

> Maybe we can run constant-evaluation before Sema::CheckForImmediateInvocation runs, though.

I think that makes sense. The _constant-expression_ that we are evaluating introduces an immediate function context that suppresses immediate invocations (https://eel.is/c++draft/expr.const#16).

Example:
```cpp
struct A {
  constexpr A(const int &x) : p(&x) {}
  const int *p;
};
consteval A a() { return {42}; }
enum { X = (a(), 0) }; // OK, no immediate invocations; Clang and GCC both accept
```

https://github.com/llvm/llvm-project/pull/90066


More information about the cfe-commits mailing list