https://github.com/akash-manna-sky created 
https://github.com/llvm/llvm-project/pull/230902

Fixes #175427

`EmitCXXNewExpr` marks the point where the operator delete cleanup becomes 
active with a placeholder `unreachable` and erases it once the initializer is 
emitted. If the initializer starts with a loop or a label, `EmitBlock` takes 
that terminator as the end of the block and emits no fall-through branch, so 
erasing the placeholder leaves the block unterminated and valid code fails with 
"Broken module found".

The marker only has to be an instruction that the deactivation can insert a 
store before, while the rest of CodeGen assumes the current block has no 
terminator until a real one is written. The placeholder is now the `i1` load 
from null that the other cleanup markers already use, so the block stays open 
and `EmitBlock` branches normally. The same marker in `EmitDelegateCallArg` is 
switched for consistency.

LLM tools were used for this contribution. I've reviewed, built, and tested the 
change myself before pushing to GitHub.


>From 25c7c1b526569a762950bb441fa2be8a8dcb2764 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Sun, 11 Oct 2026 11:28:00 +0530
Subject: [PATCH] Fixes #175427

`EmitCXXNewExpr` marks the point where the operator delete cleanup becomes 
active with a placeholder `unreachable` and erases it once the initializer is 
emitted. If the initializer starts with a loop or a label, `EmitBlock` takes 
that terminator as the end of the block and emits no fall-through branch, so 
erasing the placeholder leaves the block unterminated and valid code fails with 
"Broken module found".

The marker only has to be an instruction that the deactivation can insert a 
store before, while the rest of CodeGen assumes the current block has no 
terminator until a real one is written. The placeholder is now the `i1` load 
from null that the other cleanup markers already use, so the block stays open 
and `EmitBlock` branches normally. The same marker in `EmitDelegateCallArg` is 
switched for consistency.

LLM tools were used for this contribution. I've reviewed, built, and tested the 
change myself before pushing to GitHub.
---
 clang/docs/ReleaseNotes.md                    |   1 +
 clang/lib/CodeGen/CGCall.cpp                  |   5 +-
 clang/lib/CodeGen/CGExprCXX.cpp               |   3 +-
 .../CodeGenCXX/control-flow-in-stmt-expr.cpp  | 226 +++++++++++++++++-
 4 files changed, 231 insertions(+), 4 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 77a1e73bc8af6..bbf205a4b8efb 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -645,6 +645,7 @@ features cannot lower the translation-unit ABI level;
 - Clang now defines the GCC-compatible predefined macro `__SIG_ATOMIC_TYPE__`. 
(#GH213895)
 - Fixed IEEE f128 complex mul/div using the IBM f128 libcalls on powerpc. 
(#GH216820)
 - Fixed an ICE that occurred when a structured binding pack is expanded 
outside the lambda where it was declared. (#GH214160)
+- Fixed a crash when a statement expression in the initializer of a 
new-expression starts with a loop or a label. (#GH175427)
 - Fixed a bug where a stray closing curley brace in an OpenMP/OpenACC pragma 
could cause pragma parsing issues when inside of a member function. (#GH214195)
 - Fixed a bug where preprocessor directives following comments were not 
correctly recognized when using -C. (#GH48361)
 - Fixed a crash when declaring a member template within a local class inside 
an OpenMP region. (#GH216052)
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 1f4fd55060d39..ee453fd7f5005 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -4729,8 +4729,9 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList 
&args,
         CalleeDestructedParamCleanups.lookup(cast<ParmVarDecl>(param));
     assert(cleanup.isValid() &&
            "cleanup for callee-destructed param not recorded");
-    // This unreachable is a temporary marker which will be removed later.
-    llvm::Instruction *isActive = Builder.CreateUnreachable();
+    // This load is a temporary marker which will be removed later.
+    llvm::Instruction *isActive =
+        Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy));
     args.addArgCleanupDeactivation(cleanup, isActive);
   }
 }
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 8279611accba3..fd38a138c26cf 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -1786,7 +1786,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const 
CXXNewExpr *E) {
     EnterNewDeleteCleanup(*this, E, TypeIdentityArg, allocation, allocSize,
                           allocAlign, allocatorArgs);
     operatorDeleteCleanup = EHStack.stable_begin();
-    cleanupDominator = Builder.CreateUnreachable();
+    cleanupDominator =
+        Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy));
   }
 
   assert((allocSize == allocSizeWithoutCookie) ==
diff --git a/clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp 
b/clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp
index 9d1c9cc0a2ab6..6528b2a4c0920 100644
--- a/clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp
+++ b/clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 --std=c++20 -fexceptions -triple x86_64-linux-gnu 
-emit-llvm %s -o - | FileCheck -check-prefixes=EH %s
+// RUN: %clang_cc1 --std=c++20 -fexceptions -fcxx-exceptions -triple 
x86_64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefixes=EH %s
 // RUN: %clang_cc1 --std=c++20 -triple x86_64-linux-gnu -emit-llvm %s -o - | 
FileCheck -check-prefixes=NOEH,CHECK %s
 
 struct Printy {
@@ -518,3 +518,227 @@ void InactiveNormalCleanup() {
   // CHECK:   br label %return
 }
 }  // namespace CleanupFlag
+
+struct NoThrow {};
+void *operator new(decltype(sizeof 0), NoThrow) noexcept;
+void operator delete(void *, NoThrow) noexcept;
+
+namespace GH175427 {
+struct S {
+  S(int);
+};
+[[noreturn]] void nr();
+
+void WhileTrue() {
+  // EH-LABEL: define dso_local void @_ZN8GH1754279WhileTrueEv()
+  // EH:         call {{.*}}@_Znwm(i64 noundef 4)
+  // EH-NEXT:    br label %while.cond
+  // EH:       while.cond:
+  // EH-NEXT:    br label %while.body
+  // EH:       while.body:
+  // EH-NEXT:    br label %while.cond
+  // NOEH-LABEL: define dso_local void @_ZN8GH1754279WhileTrueEv()
+  // NOEH:         call {{.*}}@_Znwm(i64 noundef 4)
+  // NOEH-NEXT:    br label %while.body
+  // NOEH:       while.body:
+  // NOEH-NEXT:    br label %while.body
+  new int(({
+    while (true)
+      ;
+    1;
+  }));
+}
+
+void ForFirst() {
+  // EH-LABEL: define dso_local void @_ZN8GH1754278ForFirstEv()
+  // EH:         call {{.*}}@_Znwm(i64 noundef 4)
+  // EH-NEXT:    br label %for.cond
+  // EH:       for.cond:
+  // EH-NEXT:    br label %for.cond
+  new int(({
+    for (;;)
+      ;
+    1;
+  }));
+}
+
+void DoFirst() {
+  // EH-LABEL: define dso_local void @_ZN8GH1754277DoFirstEv()
+  // EH:         [[CALL:%.+]] = call {{.*}}@_Znwm(i64 noundef 4)
+  // EH-NEXT:    br label %do.body
+  // EH:       do.body:
+  // EH-NEXT:    br label %do.cond
+  // EH:       do.cond:
+  // EH-NEXT:    br i1 true, label %do.body, label %do.end
+  // EH:       do.end:
+  // EH:         store i32 {{.*}}, ptr [[CALL]]
+  // EH-NEXT:    ret void
+  new int(({
+    do
+      ;
+    while (true);
+    1;
+  }));
+}
+
+void LabelFirst() {
+  // EH-LABEL: define dso_local void @_ZN8GH17542710LabelFirstEv()
+  // EH:         [[CALL:%.+]] = call {{.*}}@_Znwm(i64 noundef 4)
+  // EH-NEXT:    br label %L
+  // EH:       L: ; preds = %entry
+  // EH-NEXT:    store i32 1, ptr [[TMP:%[^,]+]]
+  // EH-NEXT:    [[V:%.+]] = load i32, ptr [[TMP]]
+  // EH-NEXT:    store i32 [[V]], ptr [[CALL]]
+  // EH-NEXT:    ret void
+  new int(({
+  L:;
+    1;
+  }));
+}
+
+void WhileX(bool x) {
+  // EH-LABEL: define dso_local void @_ZN8GH1754276WhileXEb(
+  // EH:         [[CALL:%.+]] = call {{.*}}@_Znwm(i64 noundef 4)
+  // EH-NEXT:    br label %while.cond
+  // EH:       while.cond:
+  // EH:         br i1 {{.*}}, label %while.body, label %while.end
+  // EH:       while.body:
+  // EH-NEXT:    br label %while.cond
+  // EH:       while.end:
+  // EH:         store i32 {{.*}}, ptr [[CALL]]
+  // EH-NEXT:    ret void
+  new int(({
+    while (x)
+      ;
+    1;
+  }));
+}
+
+void ArrayNew() {
+  // EH-LABEL: define dso_local void @_ZN8GH1754278ArrayNewEv()
+  // EH:         call {{.*}}@_Znam(i64 noundef 8)
+  // EH-NEXT:    br label %while.cond
+  // EH:       while.cond:
+  // EH-NEXT:    br label %while.body
+  // EH:       while.body:
+  // EH-NEXT:    br label %while.cond
+  new int[2]{({
+    while (true)
+      ;
+    1;
+  })};
+}
+
+void ClassType() {
+  // EH-LABEL: define dso_local void @_ZN8GH1754279ClassTypeEv()
+  // EH:         [[CALL:%.+]] = call {{.*}}@_Znwm(i64 noundef 1)
+  // EH-NEXT:    br label %while.cond
+  // EH:       while.cond:
+  // EH-NEXT:    br label %while.body
+  // EH:       while.body:
+  // EH-NEXT:    br label %while.cond
+  // EH:         invoke void @_ZN8GH1754271SC1Ei(ptr {{.*}}[[CALL]], i32 
{{.*}})
+  // EH-NEXT:    to label %invoke.cont unwind label %lpad
+  // EH:       lpad:
+  // EH:         call void @_ZdlPvm(ptr noundef [[CALL]], i64 noundef 1)
+  new S(({
+    while (true)
+      ;
+    1;
+  }));
+}
+
+void NothrowNew() {
+  // EH-LABEL: define dso_local void @_ZN8GH17542710NothrowNewEv()
+  // EH:         [[CALL:%.+]] = call {{.*}}@_Znwm7NoThrow(i64 noundef 4
+  // EH-NEXT:    [[ISNULL:%.+]] = icmp eq ptr [[CALL]], null
+  // EH:         br i1 [[ISNULL]], label %new.cont, label %new.notnull
+  // EH:       new.notnull:
+  // EH:         br label %while.cond
+  // EH:       while.cond:
+  // EH-NEXT:    br label %while.body
+  // EH:       while.body:
+  // EH-NEXT:    br label %while.cond
+  // EH:       new.cont:
+  // EH-NEXT:    phi ptr [ [[CALL]], %{{.*}} ], [ null, %entry ]
+  // EH-NEXT:    ret void
+  new (NoThrow{}) int(({
+    while (true)
+      ;
+    1;
+  }));
+}
+
+void ReturnFirst() {
+  // EH-LABEL: define dso_local void @_ZN8GH17542711ReturnFirstEv()
+  // EH:         call {{.*}}@_Znwm(i64 noundef 4)
+  // EH-NEXT:    ret void
+  new int(({
+    return;
+    1;
+  }));
+}
+
+void GotoFirst() {
+  // EH-LABEL: define dso_local void @_ZN8GH1754279GotoFirstEv()
+  // EH:         call {{.*}}@_Znwm(i64 noundef 4)
+  // EH-NEXT:    br label %L
+  // EH:       L: ; preds = %entry
+  // EH-NEXT:    ret void
+  new int(({
+    goto L;
+    1;
+  }));
+L:;
+}
+
+void NoreturnFirst() {
+  // EH-LABEL: define dso_local void @_ZN8GH17542713NoreturnFirstEv()
+  // EH:         [[CALL:%.+]] = call {{.*}}@_Znwm(i64 noundef 4)
+  // EH-NEXT:    invoke void @_ZN8GH1754272nrEv()
+  // EH-NEXT:    to label %invoke.cont unwind label %lpad
+  // EH:       invoke.cont:
+  // EH-NEXT:    unreachable
+  // EH:       lpad:
+  // EH:         call void @_ZdlPvm(ptr noundef [[CALL]], i64 noundef 4)
+  new int(({
+    nr();
+    1;
+  }));
+}
+
+void UnreachableFirst() {
+  // EH-LABEL: define dso_local void @_ZN8GH17542716UnreachableFirstEv()
+  // EH:         call {{.*}}@_Znwm(i64 noundef 4)
+  // EH-NEXT:    unreachable
+  new int(({
+    __builtin_unreachable();
+    1;
+  }));
+}
+
+#if __cpp_exceptions
+void ThrowFirst() {
+  // EH-LABEL: define dso_local void @_ZN8GH17542710ThrowFirstEv()
+  // EH:         [[CALL:%.+]] = call {{.*}}@_Znwm(i64 noundef 4)
+  // EH:         invoke void @__cxa_throw(
+  // EH-NEXT:    to label %unreachable unwind label %lpad
+  // EH:       lpad:
+  // EH:         call void @_ZdlPvm(ptr noundef [[CALL]], i64 noundef 4)
+  new int(({
+    throw 1;
+    1;
+  }));
+}
+#endif
+
+void Plain() {
+  // EH-LABEL: define dso_local void @_ZN8GH1754275PlainEv()
+  // EH:         [[CALL:%.+]] = call {{.*}}@_Znwm(i64 noundef 4)
+  // EH-NEXT:    store i32 1, ptr [[TMP:%[^,]+]]
+  // EH-NEXT:    [[V:%.+]] = load i32, ptr [[TMP]]
+  // EH-NEXT:    store i32 [[V]], ptr [[CALL]]
+  // EH-NEXT:    ret void
+  new int(({ 1; }));
+}
+}  // namespace GH175427

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to