[clang] [Clang] Implement P2809: Trivial infinite loops are not Undefined Behavior (PR #90066)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 29 13:21:12 PDT 2024
================
@@ -908,6 +908,74 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
incrementProfileCounter(&S);
}
+bool CodeGenFunction::checkIfLoopMustProgress(const Expr *ControllingExpression,
+ bool IsTrivialCXXLoop) {
+ if (CGM.getCodeGenOpts().getFiniteLoops() ==
+ CodeGenOptions::FiniteLoopsKind::Always)
+ return true;
+ 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 =
+ !ControllingExpression ||
+ (ControllingExpression->EvaluateAsInt(Result, getContext()) &&
+ Result.Val.isInt());
+
+ bool CondIsTrue = CondIsConstInt &&
+ (!ControllingExpression || Result.Val.getInt().getBoolValue());
+
+ if (getLangOpts().C99 && CondIsConstInt)
+ return false;
+
+ // Loops with non-constant conditions must make progress in C11 and later.
+ if (getLangOpts().C11)
+ return true;
+
+ // [C++26][intro.progress] (DR)
+ // The implementation may assume that any thread will eventually do one of the
+ // following:
+ // [...]
+ // - continue execution of a trivial infinite loop ([stmt.iter.general]).
+ if (getLangOpts().CPlusPlus11) {
+ if (IsTrivialCXXLoop && CondIsTrue) {
+ CurFn->removeFnAttr(llvm::Attribute::MustProgress);
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+// [C++26][stmt.iter.general] (DR)
+// A trivially empty iteration statement is an iteration statement matching one
+// of the following forms:
+// - while ( expression ) ;
+// - while ( expression ) { }
+// - do ; while ( expression ) ;
+// - do { } while ( expression ) ;
+// - for ( init-statement expression(opt); ) ;
+// - for ( init-statement expression(opt); ) { }
+template <typename LoopStmt> static bool hasEmptyLoopBody(const LoopStmt &S) {
+ if constexpr (std::is_same_v<LoopStmt, ForStmt>) {
+ if (S.getInc())
+ return false;
+ }
+ const Stmt *Body = S.getBody();
+ if (!Body || isa<NullStmt>(Body))
+ return true;
+ if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body))
----------------
cor3ntin wrote:
I added some tests (and test for false conditions, which are not trivial in c++)
https://github.com/llvm/llvm-project/pull/90066
More information about the cfe-commits
mailing list