[clang] [clang][AST] Fix crash on labeled break/continue within switch condition statement expression (PR #228655)

via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 4 08:51:54 PDT 2026


https://github.com/Expertcoderz updated https://github.com/llvm/llvm-project/pull/228655

>From 13a9873c60b9e047514509b0f3b2671af89077df Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Sun, 27 Sep 2026 04:36:04 +0000
Subject: [PATCH 01/10] [clang][AST] Fix crash on labeled break/continue within
 switch condition

---
 clang/docs/ReleaseNotes.md                  |  3 ++
 clang/lib/AST/Stmt.cpp                      |  4 +-
 clang/test/CodeGen/labeled-break-continue.c | 50 +++++++++++++++++++++
 3 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 929892fd34f7f..99645faae1afb 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -822,6 +822,9 @@ features cannot lower the translation-unit ABI level;
 - Added missed information to the AST node representing the member function
   when calling a explicit object member function. (#GH218829)
 
+- Fixed a crash when encountering C2y labeled `break`/`continue` statements
+  in a statement expression within a `switch` conditon.
+
 #### Miscellaneous Bug Fixes
 
 #### Miscellaneous Clang Crashes Fixed
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index 15d0e6435aaf3..cad8ebb9d854e 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -1535,7 +1535,9 @@ const Stmt *LabelStmt::getInnermostLabeledStmt() const {
 const Stmt *LoopControlStmt::getNamedLoopOrSwitch() const {
   if (!hasLabelTarget())
     return nullptr;
-  return getLabelDecl()->getStmt()->getInnermostLabeledStmt();
+
+  LabelStmt *Label = getLabelDecl()->getStmt();
+  return Label ? Label->getInnermostLabeledStmt() : nullptr;
 }
 
 DeferStmt::DeferStmt(EmptyShell Empty) : Stmt(DeferStmtClass, Empty) {}
diff --git a/clang/test/CodeGen/labeled-break-continue.c b/clang/test/CodeGen/labeled-break-continue.c
index f307a1bd79ab8..3d050a5cc6e44 100644
--- a/clang/test/CodeGen/labeled-break-continue.c
+++ b/clang/test/CodeGen/labeled-break-continue.c
@@ -279,3 +279,53 @@ void f7() {
     }
   }
 }
+
+/// https://github.com/llvm/llvm-project/issues/184060
+// CHECK-LABEL: define {{.*}} void @f8()
+// CHECK: entry:
+// CHECK:   %tmp = alloca i32, align 4
+// CHECK:   br label %l1
+// CHECK: l1:
+// CHECK:   br label %for.cond
+// CHECK: for.cond:
+// CHECK:   br label %for.end
+// CHECK: 0:
+// CHECK:   store i32 1, ptr %tmp, align 4
+// CHECK:   %1 = load i32, ptr %tmp, align 4
+// CHECK:   switch i32 %1, label %sw.epilog [
+// CHECK:   ]
+// CHECK: sw.epilog:
+// CHECK:   call {{.*}} i1 @g1()
+// CHECK:   br label %for.cond
+// CHECK: for.end:
+// CHECK:   ret void
+void f8() {
+l1: for (;;) {
+    switch (({ break l1; 1; })) {}
+    g1();
+  }
+}
+
+/// https://github.com/llvm/llvm-project/issues/184060
+// CHECK-LABEL: define {{.*}} void @f9()
+// CHECK: entry:
+// CHECK:   %tmp = alloca i32, align 4
+// CHECK:   br label %l1
+// CHECK: l1:
+// CHECK:   br label %for.cond
+// CHECK: for.cond:
+// CHECK:   br label %for.cond
+// CHECK: 0:
+// CHECK:   store i32 1, ptr %tmp, align 4
+// CHECK:   %1 = load i32, ptr %tmp, align 4
+// CHECK:   switch i32 %1, label %sw.epilog [
+// CHECK:   ]
+// CHECK: sw.epilog:
+// CHECK:   call {{.*}} i1 @g1()
+// CHECK:   br label %for.cond
+void f9() {
+l1: for (;;) {
+    switch (({ continue l1; 1; })) {}
+    g1();
+  }
+}

>From 5f8f3640d4f20c14d0e25f34858f478a7ca3f34f Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Sun, 27 Sep 2026 07:13:17 +0000
Subject: [PATCH 02/10] Apply typo fix from @kazutakahirata

Co-authored-by: Kazu Hirata <kazu at google.com>
---
 clang/docs/ReleaseNotes.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 99645faae1afb..2c5d6dbfb4b05 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -823,7 +823,7 @@ features cannot lower the translation-unit ABI level;
   when calling a explicit object member function. (#GH218829)
 
 - Fixed a crash when encountering C2y labeled `break`/`continue` statements
-  in a statement expression within a `switch` conditon.
+  in a statement expression within a `switch` condition.
 
 #### Miscellaneous Bug Fixes
 

>From 81a8f14edb6e6bbccdacb8c2f85a35dcb4dd5e4f Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Tue, 29 Sep 2026 00:06:34 +0000
Subject: [PATCH 03/10] Add constant evaluation tests for labeled
 break/continue

---
 clang/test/SemaCXX/labeled-break-continue.cpp | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/clang/test/SemaCXX/labeled-break-continue.cpp b/clang/test/SemaCXX/labeled-break-continue.cpp
index 3d34211ed745a..d600ec5ff3caf 100644
--- a/clang/test/SemaCXX/labeled-break-continue.cpp
+++ b/clang/test/SemaCXX/labeled-break-continue.cpp
@@ -49,3 +49,21 @@ void f3() {
     };
   }
 }
+
+void f4() {
+  l1: for (;;) {
+    constexpr int x = ({ // expected-error {{constexpr variable 'x' must be initialized by a constant expression}}
+      break l1; // expected-note {{not supported in a constant expression}}
+      1;
+    });
+  }
+}
+
+void f5() {
+  l1: for (;;) {
+    constexpr int x = ({ // expected-error {{constexpr variable 'x' must be initialized by a constant expression}}
+      continue l1; // expected-note {{not supported in a constant expression}}
+      1;
+    });
+  }
+}

>From 6739068e91b5d53c1e5b024967f7587b015b8c74 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Sat, 3 Oct 2026 02:47:14 +0000
Subject: [PATCH 04/10] Move hasLabelTarget() check out of
 LoopControlStmt::getNamedLoopOrSwitch()

---
 clang/lib/AST/ByteCode/Compiler.cpp | 6 ++++--
 clang/lib/AST/ExprConstant.cpp      | 3 ++-
 clang/lib/AST/Stmt.cpp              | 4 +---
 clang/lib/CodeGen/CGStmt.cpp        | 2 +-
 4 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 01daace5b3c83..df37b705d495f 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -7184,7 +7184,8 @@ bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) {
     return false;
 
   OptLabelTy TargetLabel = std::nullopt;
-  const Stmt *TargetLoop = S->getNamedLoopOrSwitch();
+  const Stmt *TargetLoop =
+      S->hasLabelTarget() ? S->getNamedLoopOrSwitch() : nullptr;
   const VariableScope<Emitter> *BreakScope = nullptr;
 
   if (!TargetLoop) {
@@ -7224,7 +7225,8 @@ bool Compiler<Emitter>::visitContinueStmt(const ContinueStmt *S) {
     return false;
 
   OptLabelTy TargetLabel = std::nullopt;
-  const Stmt *TargetLoop = S->getNamedLoopOrSwitch();
+  const Stmt *TargetLoop =
+      S->hasLabelTarget() ? S->getNamedLoopOrSwitch() : nullptr;
   const VariableScope<Emitter> *ContinueScope = nullptr;
 
   if (!TargetLoop) {
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 3f295f35d1361..46c408c794f96 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6385,7 +6385,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
   case Stmt::ContinueStmtClass:
   case Stmt::BreakStmtClass: {
     auto *B = cast<LoopControlStmt>(S);
-    Info.BreakContinueStack.push_back(B->getNamedLoopOrSwitch());
+    Info.BreakContinueStack.push_back(
+        B->hasLabelTarget() ? B->getNamedLoopOrSwitch() : nullptr);
     return isa<ContinueStmt>(S) ? ESR_Continue : ESR_Break;
   }
 
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index cad8ebb9d854e..a8c17676d56f3 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -1533,9 +1533,7 @@ const Stmt *LabelStmt::getInnermostLabeledStmt() const {
 }
 
 const Stmt *LoopControlStmt::getNamedLoopOrSwitch() const {
-  if (!hasLabelTarget())
-    return nullptr;
-
+  assert(hasLabelTarget());
   LabelStmt *Label = getLabelDecl()->getStmt();
   return Label ? Label->getInnermostLabeledStmt() : nullptr;
 }
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 03b6e84a1c136..617929e1e613d 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -1703,7 +1703,7 @@ auto CodeGenFunction::GetDestForLoopControlStmt(const LoopControlStmt &S)
     return &BreakContinueStack.back();
 
   const Stmt *LoopOrSwitch = S.getNamedLoopOrSwitch();
-  assert(LoopOrSwitch && "break/continue target not set?");
+  assert(LoopOrSwitch && "break/continue target label not available?");
   for (const BreakContinue &BC : llvm::reverse(BreakContinueStack))
     if (BC.LoopOrSwitch == LoopOrSwitch)
       return &BC;

>From 42a778088d3fedab9187f40d97adac16c41185cf Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Sat, 3 Oct 2026 02:48:18 +0000
Subject: [PATCH 05/10] Add comment on return value of
 LoopControlStmt::getNamedLoopOrSwitch()

---
 clang/include/clang/AST/Stmt.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 5d27ded64082d..34bca3706f0a9 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3109,7 +3109,8 @@ class LoopControlStmt : public Stmt {
   void setLabelDecl(LabelDecl *S) { TargetLabel = S; }
 
   /// If this is a named break/continue, get the loop or switch statement
-  /// that this targets.
+  /// that this targets. May return null if the target LabelStmt has not
+  /// yet been created.
   const Stmt *getNamedLoopOrSwitch() const;
 
   // Iterators

>From 98d12a0395a8a94ba4cdaba06512bca5d51c6582 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Sun, 4 Oct 2026 15:15:45 +0000
Subject: [PATCH 06/10] Apply `\pre` comment suggestion from @tbaederr

Co-authored-by: Timm Baeder <tbaeder at redhat.com>
---
 clang/include/clang/AST/Stmt.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 34bca3706f0a9..6123c1c084fc1 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3111,6 +3111,7 @@ class LoopControlStmt : public Stmt {
   /// If this is a named break/continue, get the loop or switch statement
   /// that this targets. May return null if the target LabelStmt has not
   /// yet been created.
+  /// \pre `hasLabelTarget()`
   const Stmt *getNamedLoopOrSwitch() const;
 
   // Iterators

>From b38c73b80e14e485d91f74cced598240b17d26df Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Sun, 4 Oct 2026 15:17:58 +0000
Subject: [PATCH 07/10] Apply `\pre` comment suggestion from @tbaederr

Co-authored-by: Timm Baeder <tbaeder at redhat.com>
---
 clang/include/clang/AST/Stmt.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 6123c1c084fc1..019cbcb307a2a 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3113,6 +3113,7 @@ class LoopControlStmt : public Stmt {
   /// yet been created.
   /// \pre `hasLabelTarget()`
   const Stmt *getNamedLoopOrSwitch() const;
+  const Stmt *getNamedLoopOrSwitch() const;
 
   // Iterators
   child_range children() {

>From cc8fd00b44ccf74241f882d423cbfe2c578d509b Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Sun, 4 Oct 2026 15:19:39 +0000
Subject: [PATCH 08/10] Add `\pre` comment

Co-authored-by: Timm Baeder <tbaeder at redhat.com>
---
 clang/include/clang/AST/Stmt.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 019cbcb307a2a..b54ce9eddf9e1 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3114,6 +3114,7 @@ class LoopControlStmt : public Stmt {
   /// \pre `hasLabelTarget()`
   const Stmt *getNamedLoopOrSwitch() const;
   const Stmt *getNamedLoopOrSwitch() const;
+  const Stmt *getNamedLoopOrSwitch() const;
 
   // Iterators
   child_range children() {

>From d4f3afadb532d11aab7bd9aaea7c74102f4c6289 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Sun, 4 Oct 2026 15:20:46 +0000
Subject: [PATCH 09/10] Update clang/include/clang/AST/Stmt.h

Co-authored-by: Timm Baeder <tbaeder at redhat.com>
---
 clang/include/clang/AST/Stmt.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index b54ce9eddf9e1..acede8dd211ea 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3115,6 +3115,7 @@ class LoopControlStmt : public Stmt {
   const Stmt *getNamedLoopOrSwitch() const;
   const Stmt *getNamedLoopOrSwitch() const;
   const Stmt *getNamedLoopOrSwitch() const;
+  const Stmt *getNamedLoopOrSwitch() const;
 
   // Iterators
   child_range children() {

>From 8aaf3a53b13a025daa9d493c1467d594e3dc3ae5 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Sun, 4 Oct 2026 15:51:37 +0000
Subject: [PATCH 10/10] Add `\pre` comment suggestion frmo @tbaederr

Co-authored-by: Timm Baeder <tbaeder at redhat.com>
---
 clang/include/clang/AST/Stmt.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index acede8dd211ea..1a5de1f056cc5 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3116,6 +3116,7 @@ class LoopControlStmt : public Stmt {
   const Stmt *getNamedLoopOrSwitch() const;
   const Stmt *getNamedLoopOrSwitch() const;
   const Stmt *getNamedLoopOrSwitch() const;
+  const Stmt *getNamedLoopOrSwitch() const;
 
   // Iterators
   child_range children() {



More information about the cfe-commits mailing list