[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