https://github.com/Expertcoderz updated https://github.com/llvm/llvm-project/pull/228655
>From 13a9873c60b9e047514509b0f3b2671af89077df Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Sun, 27 Sep 2026 04:36:04 +0000 Subject: [PATCH 01/11] [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 <[email protected]> Date: Sun, 27 Sep 2026 07:13:17 +0000 Subject: [PATCH 02/11] Apply typo fix from @kazutakahirata Co-authored-by: Kazu Hirata <[email protected]> --- 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 <[email protected]> Date: Tue, 29 Sep 2026 00:06:34 +0000 Subject: [PATCH 03/11] 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 <[email protected]> Date: Sat, 3 Oct 2026 02:47:14 +0000 Subject: [PATCH 04/11] 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 <[email protected]> Date: Sat, 3 Oct 2026 02:48:18 +0000 Subject: [PATCH 05/11] 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 <[email protected]> Date: Sun, 4 Oct 2026 15:15:45 +0000 Subject: [PATCH 06/11] Apply `\pre` comment suggestion from @tbaederr Co-authored-by: Timm Baeder <[email protected]> --- 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 <[email protected]> Date: Sun, 4 Oct 2026 15:17:58 +0000 Subject: [PATCH 07/11] Apply `\pre` comment suggestion from @tbaederr Co-authored-by: Timm Baeder <[email protected]> --- 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 <[email protected]> Date: Sun, 4 Oct 2026 15:19:39 +0000 Subject: [PATCH 08/11] Add `\pre` comment Co-authored-by: Timm Baeder <[email protected]> --- 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 <[email protected]> Date: Sun, 4 Oct 2026 15:20:46 +0000 Subject: [PATCH 09/11] Update clang/include/clang/AST/Stmt.h Co-authored-by: Timm Baeder <[email protected]> --- 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 <[email protected]> Date: Sun, 4 Oct 2026 15:51:37 +0000 Subject: [PATCH 10/11] Add `\pre` comment suggestion frmo @tbaederr Co-authored-by: Timm Baeder <[email protected]> --- 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() { >From a2aedac4073f9a1499391295c7848b89e39260af Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Sun, 4 Oct 2026 16:28:38 +0000 Subject: [PATCH 11/11] Add proper hasLabelTarget() checks in Compiler.cpp --- clang/lib/AST/ByteCode/Compiler.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index df37b705d495f..15157db807a9d 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -7184,11 +7184,10 @@ bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) { return false; OptLabelTy TargetLabel = std::nullopt; - const Stmt *TargetLoop = - S->hasLabelTarget() ? S->getNamedLoopOrSwitch() : nullptr; const VariableScope<Emitter> *BreakScope = nullptr; - if (!TargetLoop) { + if (!S->hasLabelTarget()) { + for (const auto &LI : llvm::reverse(LabelInfoStack)) { if (LI.BreakLabel) { TargetLabel = *LI.BreakLabel; @@ -7197,6 +7196,9 @@ bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) { } } } else { + const Stmt *TargetLoop = S->getNamedLoopOrSwitch(); + assert(TargetLoop && "break target label not available"); + for (const auto &LI : LabelInfoStack) { if (LI.Name == TargetLoop) { TargetLabel = *LI.BreakLabel; @@ -7225,11 +7227,9 @@ bool Compiler<Emitter>::visitContinueStmt(const ContinueStmt *S) { return false; OptLabelTy TargetLabel = std::nullopt; - const Stmt *TargetLoop = - S->hasLabelTarget() ? S->getNamedLoopOrSwitch() : nullptr; const VariableScope<Emitter> *ContinueScope = nullptr; - if (!TargetLoop) { + if (!S->hasLabelTarget()) { for (const auto &LI : llvm::reverse(LabelInfoStack)) { if (LI.ContinueLabel) { TargetLabel = *LI.ContinueLabel; @@ -7238,6 +7238,9 @@ bool Compiler<Emitter>::visitContinueStmt(const ContinueStmt *S) { } } } else { + const Stmt *TargetLoop = S->getNamedLoopOrSwitch(); + assert(TargetLoop && "continue target label not available"); + for (auto LI : LabelInfoStack) { if (LI.Name == TargetLoop) { TargetLabel = *LI.ContinueLabel; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
