[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
Wed Oct 14 04:32:59 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/30] [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 929892fd34f7fc..99645faae1afb4 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 15d0e6435aaf3a..cad8ebb9d854e2 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 f307a1bd79ab8c..3d050a5cc6e44d 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/30] 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 99645faae1afb4..2c5d6dbfb4b052 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/30] 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 3d34211ed745a9..d600ec5ff3cafd 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/30] 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 01daace5b3c83e..df37b705d495f4 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 3f295f35d1361a..46c408c794f960 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 cad8ebb9d854e2..a8c17676d56f33 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 03b6e84a1c136c..617929e1e613d8 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/30] 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 5d27ded64082da..34bca3706f0a9f 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/30] 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 34bca3706f0a9f..6123c1c084fc13 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/30] 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 6123c1c084fc13..019cbcb307a2a2 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/30] 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 019cbcb307a2a2..b54ce9eddf9e16 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/30] 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 b54ce9eddf9e16..acede8dd211ea0 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/30] 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 acede8dd211ea0..1a5de1f056cc51 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 <expertcoderzx at gmail.com>
Date: Sun, 4 Oct 2026 16:28:38 +0000
Subject: [PATCH 11/30] 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 df37b705d495f4..15157db807a9d3 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;
>From 86548035313614fcd7bcfccdcf6c72e33741dbf5 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Sun, 4 Oct 2026 16:48:27 +0000
Subject: [PATCH 12/30] Fix duplicated function declaration due to github bug
---
clang/include/clang/AST/Stmt.h | 4 ----
1 file changed, 4 deletions(-)
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 1a5de1f056cc51..6123c1c084fc13 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3113,10 +3113,6 @@ class LoopControlStmt : public Stmt {
/// yet been created.
/// \pre `hasLabelTarget()`
const Stmt *getNamedLoopOrSwitch() const;
- const Stmt *getNamedLoopOrSwitch() const;
- const Stmt *getNamedLoopOrSwitch() const;
- const Stmt *getNamedLoopOrSwitch() const;
- const Stmt *getNamedLoopOrSwitch() const;
// Iterators
child_range children() {
>From a273c6909fd8b504649cae8ffff1720cadffb14b Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Tue, 6 Oct 2026 07:28:55 +0000
Subject: [PATCH 13/30] Add labeled-break-continue test run with new constant
interpreter
---
clang/test/CodeGen/labeled-break-continue.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/test/CodeGen/labeled-break-continue.c b/clang/test/CodeGen/labeled-break-continue.c
index 3d050a5cc6e44d..9c76a9ea7e8874 100644
--- a/clang/test/CodeGen/labeled-break-continue.c
+++ b/clang/test/CodeGen/labeled-break-continue.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c2y -triple x86_64-unknown-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c2y -triple x86_64-unknown-linux -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s
bool g1();
bool g2();
>From 1e0bba2816f3d4bdd69ac94030c7f04829010706 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Tue, 6 Oct 2026 07:34:01 +0000
Subject: [PATCH 14/30] Rename hasLabelTarget() to isNamed() for better clarity
---
clang/include/clang/AST/Stmt.h | 6 +++---
clang/lib/AST/ASTImporter.cpp | 4 ++--
clang/lib/AST/ByteCode/Compiler.cpp | 4 ++--
clang/lib/AST/ExprConstant.cpp | 4 ++--
clang/lib/AST/JSONNodeDumper.cpp | 2 +-
clang/lib/AST/Stmt.cpp | 2 +-
clang/lib/AST/StmtPrinter.cpp | 4 ++--
clang/lib/AST/TextNodeDumper.cpp | 2 +-
clang/lib/CodeGen/CGStmt.cpp | 2 +-
clang/lib/Sema/TreeTransform.h | 4 ++--
clang/lib/Serialization/ASTWriterStmt.cpp | 4 ++--
11 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 6123c1c084fc13..00a415560b8990 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3096,10 +3096,10 @@ class LoopControlStmt : public Stmt {
SourceLocation getBeginLoc() const { return getKwLoc(); }
SourceLocation getEndLoc() const {
- return hasLabelTarget() ? getLabelLoc() : getKwLoc();
+ return isNamed() ? getLabelLoc() : getKwLoc();
}
- bool hasLabelTarget() const { return TargetLabel != nullptr; }
+ bool isNamed() const { return TargetLabel != nullptr; }
SourceLocation getLabelLoc() const { return LabelLoc; }
void setLabelLoc(SourceLocation L) { LabelLoc = L; }
@@ -3111,7 +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()`
+ /// \pre `isNamed()`
const Stmt *getNamedLoopOrSwitch() const;
// Iterators
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 4c296b6829b1b0..9d6c824fe627de 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -7333,10 +7333,10 @@ static ExpectedStmt ImportLoopControlStmt(ASTNodeImporter &NodeImporter,
ASTImporter &Importer, StmtClass *S) {
Error Err = Error::success();
auto ToLoc = NodeImporter.importChecked(Err, S->getKwLoc());
- auto ToLabelLoc = S->hasLabelTarget()
+ auto ToLabelLoc = S->isNamed()
? NodeImporter.importChecked(Err, S->getLabelLoc())
: SourceLocation();
- auto ToDecl = S->hasLabelTarget()
+ auto ToDecl = S->isNamed()
? NodeImporter.importChecked(Err, S->getLabelDecl())
: nullptr;
if (Err)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 15157db807a9d3..94c12c15339daf 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -7186,7 +7186,7 @@ bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) {
OptLabelTy TargetLabel = std::nullopt;
const VariableScope<Emitter> *BreakScope = nullptr;
- if (!S->hasLabelTarget()) {
+ if (!S->isNamed()) {
for (const auto &LI : llvm::reverse(LabelInfoStack)) {
if (LI.BreakLabel) {
@@ -7229,7 +7229,7 @@ bool Compiler<Emitter>::visitContinueStmt(const ContinueStmt *S) {
OptLabelTy TargetLabel = std::nullopt;
const VariableScope<Emitter> *ContinueScope = nullptr;
- if (!S->hasLabelTarget()) {
+ if (!S->isNamed()) {
for (const auto &LI : llvm::reverse(LabelInfoStack)) {
if (LI.ContinueLabel) {
TargetLabel = *LI.ContinueLabel;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 46c408c794f960..7eff997d414d62 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6385,8 +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->hasLabelTarget() ? B->getNamedLoopOrSwitch() : nullptr);
+ Info.BreakContinueStack.push_back(B->isNamed() ? B->getNamedLoopOrSwitch()
+ : nullptr);
return isa<ContinueStmt>(S) ? ESR_Continue : ESR_Break;
}
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index 4cea437db41507..75abc4777f717f 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -1750,7 +1750,7 @@ void JSONNodeDumper::VisitLabelStmt(const LabelStmt *LS) {
}
void JSONNodeDumper::VisitLoopControlStmt(const LoopControlStmt *LS) {
- if (LS->hasLabelTarget())
+ if (LS->isNamed())
JOS.attribute("targetLabelDeclId",
createPointerRepresentation(LS->getLabelDecl()));
}
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index a8c17676d56f33..10dd9e247c135c 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -1533,7 +1533,7 @@ const Stmt *LabelStmt::getInnermostLabeledStmt() const {
}
const Stmt *LoopControlStmt::getNamedLoopOrSwitch() const {
- assert(hasLabelTarget());
+ assert(isNamed());
LabelStmt *Label = getLabelDecl()->getStmt();
return Label ? Label->getInnermostLabeledStmt() : nullptr;
}
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index fcc7ee74474cfa..4f184868659f48 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -507,7 +507,7 @@ void StmtPrinter::VisitIndirectGotoStmt(IndirectGotoStmt *Node) {
void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) {
Indent();
- if (Node->hasLabelTarget())
+ if (Node->isNamed())
OS << "continue " << Node->getLabelDecl()->getIdentifier()->getName()
<< ';';
else
@@ -517,7 +517,7 @@ void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) {
void StmtPrinter::VisitBreakStmt(BreakStmt *Node) {
Indent();
- if (Node->hasLabelTarget())
+ if (Node->isNamed())
OS << "break " << Node->getLabelDecl()->getIdentifier()->getName() << ';';
else
OS << "break;";
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index d7476eacbd27a0..497fca228e428d 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1522,7 +1522,7 @@ void TextNodeDumper::dumpLinkageAndVisibility(const NamedDecl *ND) {
}
void TextNodeDumper::VisitLoopControlStmt(const LoopControlStmt *Node) {
- if (!Node->hasLabelTarget())
+ if (!Node->isNamed())
return;
OS << " '" << Node->getLabelDecl()->getIdentifier()->getName() << "' (";
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 617929e1e613d8..b08220c5ed627d 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -1699,7 +1699,7 @@ void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
auto CodeGenFunction::GetDestForLoopControlStmt(const LoopControlStmt &S)
-> const BreakContinue * {
- if (!S.hasLabelTarget())
+ if (!S.isNamed())
return &BreakContinueStack.back();
const Stmt *LoopOrSwitch = S.getNamedLoopOrSwitch();
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 73367d6bea063d..628dd62a65c1c6 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -8792,7 +8792,7 @@ TreeTransform<Derived>::TransformIndirectGotoStmt(IndirectGotoStmt *S) {
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformContinueStmt(ContinueStmt *S) {
- if (!S->hasLabelTarget())
+ if (!S->isNamed())
return S;
Decl *LD = getDerived().TransformDecl(S->getLabelDecl()->getLocation(),
@@ -8807,7 +8807,7 @@ TreeTransform<Derived>::TransformContinueStmt(ContinueStmt *S) {
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformBreakStmt(BreakStmt *S) {
- if (!S->hasLabelTarget())
+ if (!S->isNamed())
return S;
Decl *LD = getDerived().TransformDecl(S->getLabelDecl()->getLocation(),
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 4b4d179fb406ac..c6f04336f806ee 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -314,8 +314,8 @@ void ASTStmtWriter::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
void ASTStmtWriter::VisitLoopControlStmt(LoopControlStmt *S) {
VisitStmt(S);
Record.AddSourceLocation(S->getKwLoc());
- Record.push_back(S->hasLabelTarget());
- if (S->hasLabelTarget()) {
+ Record.push_back(S->isNamed());
+ if (S->isNamed()) {
Record.AddDeclRef(S->getLabelDecl());
Record.AddSourceLocation(S->getLabelLoc());
}
>From b582bae944bda3600bf64a44aad5d37066f26015 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Tue, 6 Oct 2026 08:20:30 +0000
Subject: [PATCH 15/30] Fix test
---
clang/test/CodeGen/labeled-break-continue.c | 1 -
clang/test/SemaCXX/labeled-break-continue.cpp | 3 ++-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/CodeGen/labeled-break-continue.c b/clang/test/CodeGen/labeled-break-continue.c
index 9c76a9ea7e8874..3d050a5cc6e44d 100644
--- a/clang/test/CodeGen/labeled-break-continue.c
+++ b/clang/test/CodeGen/labeled-break-continue.c
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -std=c2y -triple x86_64-unknown-linux -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -std=c2y -triple x86_64-unknown-linux -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s
bool g1();
bool g2();
diff --git a/clang/test/SemaCXX/labeled-break-continue.cpp b/clang/test/SemaCXX/labeled-break-continue.cpp
index d600ec5ff3cafd..7d1511a5a9e3db 100644
--- a/clang/test/SemaCXX/labeled-break-continue.cpp
+++ b/clang/test/SemaCXX/labeled-break-continue.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++20 -verify -fsyntax-only -fnamed-loops %s
+// RUN: %clang_cc1 -std=c++20 -verify -fsyntax-only -fnamed-loops %s -fno-experimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++20 -verify -fsyntax-only -fnamed-loops %s -fexperimental-new-constant-interpreter
int a[10]{};
struct S {
>From a6bdc1f0a229cc52ffbb4b86381260960e57e8d2 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Tue, 6 Oct 2026 11:20:23 +0000
Subject: [PATCH 16/30] Change return type of getNamedLoopOrSwitch() to
std::optional<Stmt *>
---
clang/include/clang/AST/Stmt.h | 2 +-
clang/lib/AST/ByteCode/Compiler.cpp | 8 ++++----
clang/lib/AST/ExprConstant.cpp | 4 ++--
clang/lib/AST/Stmt.cpp | 5 +++--
clang/lib/AST/TextNodeDumper.cpp | 6 +++---
clang/lib/CodeGen/CGStmt.cpp | 4 ++--
6 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 00a415560b8990..39ffa4f4dfc45f 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3112,7 +3112,7 @@ class LoopControlStmt : public Stmt {
/// that this targets. May return null if the target LabelStmt has not
/// yet been created.
/// \pre `isNamed()`
- const Stmt *getNamedLoopOrSwitch() const;
+ const std::optional<Stmt *> getNamedLoopOrSwitch() const;
// Iterators
child_range children() {
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 94c12c15339daf..b3f0943b2bb87e 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -7196,11 +7196,11 @@ bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) {
}
}
} else {
- const Stmt *TargetLoop = S->getNamedLoopOrSwitch();
+ const std::optional<Stmt *> TargetLoop = S->getNamedLoopOrSwitch();
assert(TargetLoop && "break target label not available");
for (const auto &LI : LabelInfoStack) {
- if (LI.Name == TargetLoop) {
+ if (LI.Name == TargetLoop.value()) {
TargetLabel = *LI.BreakLabel;
BreakScope = LI.BreakOrContinueScope;
break;
@@ -7238,11 +7238,11 @@ bool Compiler<Emitter>::visitContinueStmt(const ContinueStmt *S) {
}
}
} else {
- const Stmt *TargetLoop = S->getNamedLoopOrSwitch();
+ const std::optional<Stmt *> TargetLoop = S->getNamedLoopOrSwitch();
assert(TargetLoop && "continue target label not available");
for (auto LI : LabelInfoStack) {
- if (LI.Name == TargetLoop) {
+ if (LI.Name == TargetLoop.value()) {
TargetLabel = *LI.ContinueLabel;
ContinueScope = LI.BreakOrContinueScope;
break;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 7eff997d414d62..354d80fed9bc54 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6385,8 +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->isNamed() ? B->getNamedLoopOrSwitch()
- : nullptr);
+ Info.BreakContinueStack.push_back(
+ B->isNamed() ? B->getNamedLoopOrSwitch().value_or(nullptr) : nullptr);
return isa<ContinueStmt>(S) ? ESR_Continue : ESR_Break;
}
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index 10dd9e247c135c..eaf2b86ca323fb 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -1532,10 +1532,11 @@ const Stmt *LabelStmt::getInnermostLabeledStmt() const {
return S;
}
-const Stmt *LoopControlStmt::getNamedLoopOrSwitch() const {
+const std::optional<Stmt *> LoopControlStmt::getNamedLoopOrSwitch() const {
assert(isNamed());
LabelStmt *Label = getLabelDecl()->getStmt();
- return Label ? Label->getInnermostLabeledStmt() : nullptr;
+ return Label ? std::optional<Stmt *>(Label->getInnermostLabeledStmt())
+ : std::nullopt;
}
DeferStmt::DeferStmt(EmptyShell Empty) : Stmt(DeferStmtClass, Empty) {}
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 497fca228e428d..53b0929a96147b 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1527,16 +1527,16 @@ void TextNodeDumper::VisitLoopControlStmt(const LoopControlStmt *Node) {
OS << " '" << Node->getLabelDecl()->getIdentifier()->getName() << "' (";
- auto *Target = Node->getNamedLoopOrSwitch();
+ const std::optional<Stmt *> Target = Node->getNamedLoopOrSwitch();
if (!Target) {
ColorScope Color(OS, ShowColors, ASTDumpColor::Null);
OS << "<<<NULL>>>";
} else {
{
ColorScope Color(OS, ShowColors, ASTDumpColor::Stmt);
- OS << Target->getStmtClassName();
+ OS << Target.value()->getStmtClassName();
}
- dumpPointer(Target);
+ dumpPointer(Target.value());
}
OS << ")";
}
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index b08220c5ed627d..ec8c6e9bad7b0e 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -1702,10 +1702,10 @@ auto CodeGenFunction::GetDestForLoopControlStmt(const LoopControlStmt &S)
if (!S.isNamed())
return &BreakContinueStack.back();
- const Stmt *LoopOrSwitch = S.getNamedLoopOrSwitch();
+ const std::optional<Stmt *> LoopOrSwitch = S.getNamedLoopOrSwitch();
assert(LoopOrSwitch && "break/continue target label not available?");
for (const BreakContinue &BC : llvm::reverse(BreakContinueStack))
- if (BC.LoopOrSwitch == LoopOrSwitch)
+ if (BC.LoopOrSwitch == LoopOrSwitch.value())
return &BC;
llvm_unreachable("break/continue target not found");
>From 0d98ee013bdc6b31bc00e7fb3e210254b2668b15 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Tue, 6 Oct 2026 11:31:23 +0000
Subject: [PATCH 17/30] Update comment on getNamedLoopOrSwitch()
---
clang/include/clang/AST/Stmt.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 39ffa4f4dfc45f..9dbeb7d058a957 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3109,8 +3109,9 @@ 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. May return null if the target LabelStmt has not
- /// yet been created.
+ /// that this targets. May return std::nullopt if the loop has a label
+ /// but its LabelStmt has not yet been created. Otherwise, Stmt * will
+ /// be a non-null pointer to the loop or switch statement under the label.
/// \pre `isNamed()`
const std::optional<Stmt *> getNamedLoopOrSwitch() const;
>From 6757a76a1b2100abc6d0bacd96b90d54a83a1966 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Thu, 8 Oct 2026 00:22:51 +0000
Subject: [PATCH 18/30] Make the diagnostic note optional in constant
expression tests
---
clang/test/SemaCXX/labeled-break-continue.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/test/SemaCXX/labeled-break-continue.cpp b/clang/test/SemaCXX/labeled-break-continue.cpp
index 7d1511a5a9e3db..c184d42e63eaa5 100644
--- a/clang/test/SemaCXX/labeled-break-continue.cpp
+++ b/clang/test/SemaCXX/labeled-break-continue.cpp
@@ -46,7 +46,7 @@ void f3() {
a: while (true) {
(void) []{
break a; // expected-error {{'break' label does not name an enclosing loop or 'switch'}}
- continue a; // expected-error {{'continue' label does not name an enclosing loop}}
+ continue a; // expected-error 0-1 {{'continue' label does not name an enclosing loop}}
};
}
}
@@ -54,7 +54,7 @@ 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}}
+ break l1; // expected-note 0-1 {{not supported in a constant expression}}
1;
});
}
@@ -63,7 +63,7 @@ void f4() {
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}}
+ continue l1; // expected-note 0-1 {{not supported in a constant expression}}
1;
});
}
>From eda7925c13e9e9552ee78dc7c0ef6d9754355a17 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Thu, 8 Oct 2026 00:43:41 +0000
Subject: [PATCH 19/30] Fix typo
---
clang/test/SemaCXX/labeled-break-continue.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/SemaCXX/labeled-break-continue.cpp b/clang/test/SemaCXX/labeled-break-continue.cpp
index c184d42e63eaa5..32c5962d870335 100644
--- a/clang/test/SemaCXX/labeled-break-continue.cpp
+++ b/clang/test/SemaCXX/labeled-break-continue.cpp
@@ -46,7 +46,7 @@ void f3() {
a: while (true) {
(void) []{
break a; // expected-error {{'break' label does not name an enclosing loop or 'switch'}}
- continue a; // expected-error 0-1 {{'continue' label does not name an enclosing loop}}
+ continue a; // expected-error {{'continue' label does not name an enclosing loop}}
};
}
}
>From 6517344123cd69e384feb19c724b5e72f7401e8e Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Thu, 8 Oct 2026 01:49:27 +0000
Subject: [PATCH 20/30] Use -verify=... for tests with new constant interpreter
---
clang/test/SemaCXX/labeled-break-continue.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/test/SemaCXX/labeled-break-continue.cpp b/clang/test/SemaCXX/labeled-break-continue.cpp
index 32c5962d870335..2002174efcb624 100644
--- a/clang/test/SemaCXX/labeled-break-continue.cpp
+++ b/clang/test/SemaCXX/labeled-break-continue.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++20 -verify -fsyntax-only -fnamed-loops %s -fno-experimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++20 -verify=expected,no-new-interp -fsyntax-only -fnamed-loops %s -fno-experimental-new-constant-interpreter
// RUN: %clang_cc1 -std=c++20 -verify -fsyntax-only -fnamed-loops %s -fexperimental-new-constant-interpreter
int a[10]{};
@@ -54,7 +54,7 @@ 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 0-1 {{not supported in a constant expression}}
+ break l1; // no-new-interp-note {{not supported in a constant expression}}
1;
});
}
@@ -63,7 +63,7 @@ void f4() {
void f5() {
l1: for (;;) {
constexpr int x = ({ // expected-error {{constexpr variable 'x' must be initialized by a constant expression}}
- continue l1; // expected-note 0-1 {{not supported in a constant expression}}
+ continue l1; // no-new-interp-note {{not supported in a constant expression}}
1;
});
}
>From f1cd0e894e76b38acfc1de43a64e8f9d5d95c3f0 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Fri, 9 Oct 2026 01:45:57 +0000
Subject: [PATCH 21/30] Revert "Change return type of getNamedLoopOrSwitch() to
std::optional<Stmt *>"
This reverts commit a6bdc1f0a229cc52ffbb4b86381260960e57e8d2.
---
clang/include/clang/AST/Stmt.h | 2 +-
clang/lib/AST/ByteCode/Compiler.cpp | 8 ++++----
clang/lib/AST/ExprConstant.cpp | 4 ++--
clang/lib/AST/Stmt.cpp | 5 ++---
clang/lib/AST/TextNodeDumper.cpp | 6 +++---
clang/lib/CodeGen/CGStmt.cpp | 4 ++--
6 files changed, 14 insertions(+), 15 deletions(-)
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 9dbeb7d058a957..e5548f9f18e10f 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3113,7 +3113,7 @@ class LoopControlStmt : public Stmt {
/// but its LabelStmt has not yet been created. Otherwise, Stmt * will
/// be a non-null pointer to the loop or switch statement under the label.
/// \pre `isNamed()`
- const std::optional<Stmt *> getNamedLoopOrSwitch() const;
+ const Stmt *getNamedLoopOrSwitch() const;
// Iterators
child_range children() {
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index b3f0943b2bb87e..94c12c15339daf 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -7196,11 +7196,11 @@ bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) {
}
}
} else {
- const std::optional<Stmt *> TargetLoop = S->getNamedLoopOrSwitch();
+ const Stmt *TargetLoop = S->getNamedLoopOrSwitch();
assert(TargetLoop && "break target label not available");
for (const auto &LI : LabelInfoStack) {
- if (LI.Name == TargetLoop.value()) {
+ if (LI.Name == TargetLoop) {
TargetLabel = *LI.BreakLabel;
BreakScope = LI.BreakOrContinueScope;
break;
@@ -7238,11 +7238,11 @@ bool Compiler<Emitter>::visitContinueStmt(const ContinueStmt *S) {
}
}
} else {
- const std::optional<Stmt *> TargetLoop = S->getNamedLoopOrSwitch();
+ const Stmt *TargetLoop = S->getNamedLoopOrSwitch();
assert(TargetLoop && "continue target label not available");
for (auto LI : LabelInfoStack) {
- if (LI.Name == TargetLoop.value()) {
+ if (LI.Name == TargetLoop) {
TargetLabel = *LI.ContinueLabel;
ContinueScope = LI.BreakOrContinueScope;
break;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 354d80fed9bc54..7eff997d414d62 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6385,8 +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->isNamed() ? B->getNamedLoopOrSwitch().value_or(nullptr) : nullptr);
+ Info.BreakContinueStack.push_back(B->isNamed() ? 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 eaf2b86ca323fb..10dd9e247c135c 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -1532,11 +1532,10 @@ const Stmt *LabelStmt::getInnermostLabeledStmt() const {
return S;
}
-const std::optional<Stmt *> LoopControlStmt::getNamedLoopOrSwitch() const {
+const Stmt *LoopControlStmt::getNamedLoopOrSwitch() const {
assert(isNamed());
LabelStmt *Label = getLabelDecl()->getStmt();
- return Label ? std::optional<Stmt *>(Label->getInnermostLabeledStmt())
- : std::nullopt;
+ return Label ? Label->getInnermostLabeledStmt() : nullptr;
}
DeferStmt::DeferStmt(EmptyShell Empty) : Stmt(DeferStmtClass, Empty) {}
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 53b0929a96147b..497fca228e428d 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1527,16 +1527,16 @@ void TextNodeDumper::VisitLoopControlStmt(const LoopControlStmt *Node) {
OS << " '" << Node->getLabelDecl()->getIdentifier()->getName() << "' (";
- const std::optional<Stmt *> Target = Node->getNamedLoopOrSwitch();
+ auto *Target = Node->getNamedLoopOrSwitch();
if (!Target) {
ColorScope Color(OS, ShowColors, ASTDumpColor::Null);
OS << "<<<NULL>>>";
} else {
{
ColorScope Color(OS, ShowColors, ASTDumpColor::Stmt);
- OS << Target.value()->getStmtClassName();
+ OS << Target->getStmtClassName();
}
- dumpPointer(Target.value());
+ dumpPointer(Target);
}
OS << ")";
}
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index ec8c6e9bad7b0e..b08220c5ed627d 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -1702,10 +1702,10 @@ auto CodeGenFunction::GetDestForLoopControlStmt(const LoopControlStmt &S)
if (!S.isNamed())
return &BreakContinueStack.back();
- const std::optional<Stmt *> LoopOrSwitch = S.getNamedLoopOrSwitch();
+ const Stmt *LoopOrSwitch = S.getNamedLoopOrSwitch();
assert(LoopOrSwitch && "break/continue target label not available?");
for (const BreakContinue &BC : llvm::reverse(BreakContinueStack))
- if (BC.LoopOrSwitch == LoopOrSwitch.value())
+ if (BC.LoopOrSwitch == LoopOrSwitch)
return &BC;
llvm_unreachable("break/continue target not found");
>From 5360a46da57e934e2cdac953fa36f35f9f9b6f3f Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Fri, 9 Oct 2026 09:00:09 +0000
Subject: [PATCH 22/30] Revert "Update comment on getNamedLoopOrSwitch()"
This reverts commit 0d98ee013bdc6b31bc00e7fb3e210254b2668b15.
---
clang/include/clang/AST/Stmt.h | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index e5548f9f18e10f..00a415560b8990 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3109,9 +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. May return std::nullopt if the loop has a label
- /// but its LabelStmt has not yet been created. Otherwise, Stmt * will
- /// be a non-null pointer to the loop or switch statement under the label.
+ /// that this targets. May return null if the target LabelStmt has not
+ /// yet been created.
/// \pre `isNamed()`
const Stmt *getNamedLoopOrSwitch() const;
>From 86096626f46b2dc9abda15ec42d1ada2018e3620 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Fri, 9 Oct 2026 09:24:40 +0000
Subject: [PATCH 23/30] Clarify comment on getNamedLoopOrSwtich()
---
clang/include/clang/AST/Stmt.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 00a415560b8990..22679897f9f926 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3110,7 +3110,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.
+ /// yet been created. Do not call if this is an unnamed break/continue.
/// \pre `isNamed()`
const Stmt *getNamedLoopOrSwitch() const;
>From 63d73b1c85383b71fd8e59a6892f8d3e5d6acf0c Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Fri, 9 Oct 2026 23:39:15 +0000
Subject: [PATCH 24/30] Change wording in getNamedLoopOrSwitch() comment
Co-authored-by: Ambrose Leeb <aeternalmail at gmail.com>
---
clang/include/clang/AST/Stmt.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 22679897f9f926..312e664c669c3d 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3110,7 +3110,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. Do not call if this is an unnamed break/continue.
+ /// yet been created. Asserts if this is an unnamed break/continue.
/// \pre `isNamed()`
const Stmt *getNamedLoopOrSwitch() const;
>From 57c2dcabbcdce17457699a84e4d39fb12a1cef1f Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Sat, 10 Oct 2026 00:28:47 +0000
Subject: [PATCH 25/30] Fix handling of named break/continue within constexpr
loops
---
clang/lib/AST/ByteCode/Compiler.cpp | 6 ++++--
clang/lib/AST/ExprConstant.cpp | 13 +++++++++++--
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 94c12c15339daf..52d4dcb1c2cf64 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -7197,7 +7197,8 @@ bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) {
}
} else {
const Stmt *TargetLoop = S->getNamedLoopOrSwitch();
- assert(TargetLoop && "break target label not available");
+ if (!TargetLoop)
+ return this->emitUnsupported(S);
for (const auto &LI : LabelInfoStack) {
if (LI.Name == TargetLoop) {
@@ -7239,7 +7240,8 @@ bool Compiler<Emitter>::visitContinueStmt(const ContinueStmt *S) {
}
} else {
const Stmt *TargetLoop = S->getNamedLoopOrSwitch();
- assert(TargetLoop && "continue target label not available");
+ if (!TargetLoop)
+ return this->emitUnsupported(S);
for (auto LI : LabelInfoStack) {
if (LI.Name == TargetLoop) {
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 7eff997d414d62..81da74215b23fd 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6385,8 +6385,17 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
case Stmt::ContinueStmtClass:
case Stmt::BreakStmtClass: {
auto *B = cast<LoopControlStmt>(S);
- Info.BreakContinueStack.push_back(B->isNamed() ? B->getNamedLoopOrSwitch()
- : nullptr);
+ const Stmt *LoopOrSwitch = nullptr;
+ if (B->isNamed()) {
+ LoopOrSwitch = B->getNamedLoopOrSwitch();
+ if (!LoopOrSwitch) {
+ Info.FFDiag(S->getBeginLoc(),
+ diag::note_constexpr_stmt_expr_unsupported);
+ return ESR_Failed;
+ }
+ }
+
+ Info.BreakContinueStack.push_back(LoopOrSwitch);
return isa<ContinueStmt>(S) ? ESR_Continue : ESR_Break;
}
>From bf61f3d7adf6efd4d339fb01c979cbeae118ff23 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Sat, 10 Oct 2026 00:29:11 +0000
Subject: [PATCH 26/30] Add tests for named break/continue within constexpr
loops
---
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 2002174efcb624..08036d1bb3b3d9 100644
--- a/clang/test/SemaCXX/labeled-break-continue.cpp
+++ b/clang/test/SemaCXX/labeled-break-continue.cpp
@@ -68,3 +68,21 @@ void f5() {
});
}
}
+
+void f6() {
+ l1: for (;;) {
+ constexpr int x = ({ // expected-error {{constexpr variable 'x' must be initialized by a constant expression}}
+ for (;;) break l1; // expected-note {{not supported in a constant expression}}
+ 1;
+ });
+ }
+}
+
+void f7() {
+ l1: for (;;) {
+ constexpr int x = ({ // expected-error {{constexpr variable 'x' must be initialized by a constant expression}}
+ for (;;) continue l1; // expected-note {{not supported in a constant expression}}
+ 1;
+ });
+ }
+}
>From 75cc86c79ce82a3f70d84eac17e10169bb79a490 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Tue, 13 Oct 2026 14:35:21 +0000
Subject: [PATCH 27/30] Add comments on treatment of getNamedLoopOrSwitch()
return values
---
clang/lib/AST/ByteCode/Compiler.cpp | 4 ++++
clang/lib/AST/ExprConstant.cpp | 2 ++
2 files changed, 6 insertions(+)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 52d4dcb1c2cf64..c35ecd13c14d16 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -7197,6 +7197,8 @@ bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) {
}
} else {
const Stmt *TargetLoop = S->getNamedLoopOrSwitch();
+ // May be null if the named loop is outside of the
+ // current evaluation context, i.e. not a valid target.
if (!TargetLoop)
return this->emitUnsupported(S);
@@ -7240,6 +7242,8 @@ bool Compiler<Emitter>::visitContinueStmt(const ContinueStmt *S) {
}
} else {
const Stmt *TargetLoop = S->getNamedLoopOrSwitch();
+ // May be null if the named loop is outside of the
+ // current evaluation context, i.e. not a valid target.
if (!TargetLoop)
return this->emitUnsupported(S);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 81da74215b23fd..d6927cee293129 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6388,6 +6388,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
const Stmt *LoopOrSwitch = nullptr;
if (B->isNamed()) {
LoopOrSwitch = B->getNamedLoopOrSwitch();
+ // May be null if the named loop is outside of the
+ // current evaluation context, i.e. not a valid target.
if (!LoopOrSwitch) {
Info.FFDiag(S->getBeginLoc(),
diag::note_constexpr_stmt_expr_unsupported);
>From 7f454d8fab969cfac318acf50f1c96ab806486ba Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Tue, 13 Oct 2026 16:18:22 +0000
Subject: [PATCH 28/30] Improve diagnostic for break/continue targets in
constant expressions
---
clang/include/clang/Basic/DiagnosticASTKinds.td | 4 ++++
clang/lib/AST/ByteCode/Compiler.cpp | 8 ++++----
clang/lib/AST/ByteCode/Interp.h | 7 +++++++
clang/lib/AST/ByteCode/Opcodes.td | 4 ++++
clang/lib/AST/ExprConstant.cpp | 3 ++-
clang/test/SemaCXX/labeled-break-continue.cpp | 10 +++++-----
6 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 0aca1f75428f8a..8058241a3866a0 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -448,6 +448,10 @@ def err_invalid_is_within_lifetime : Note<
"a pointer to an object whose lifetime has not yet begun}1"
>;
+def note_break_continue_label_outside_context : Note<
+ "cannot %select{break|continue}0 to a label outside "
+ "the current evaluation context">;
+
// inline asm related.
let CategoryName = "Inline Assembly Issue" in {
def err_asm_invalid_escape : Error<
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index c35ecd13c14d16..2d87e41cc51c16 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -7181,7 +7181,7 @@ bool Compiler<Emitter>::visitCXXForRangeStmt(const CXXForRangeStmt *S) {
template <class Emitter>
bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) {
if (LabelInfoStack.empty())
- return false;
+ return this->emitInvalidTargetLabel(/*IsContinue=*/false, S);
OptLabelTy TargetLabel = std::nullopt;
const VariableScope<Emitter> *BreakScope = nullptr;
@@ -7200,7 +7200,7 @@ bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) {
// May be null if the named loop is outside of the
// current evaluation context, i.e. not a valid target.
if (!TargetLoop)
- return this->emitUnsupported(S);
+ return this->emitInvalidTargetLabel(/*IsContinue=*/false, S);
for (const auto &LI : LabelInfoStack) {
if (LI.Name == TargetLoop) {
@@ -7227,7 +7227,7 @@ bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) {
template <class Emitter>
bool Compiler<Emitter>::visitContinueStmt(const ContinueStmt *S) {
if (LabelInfoStack.empty())
- return false;
+ return this->emitInvalidTargetLabel(/*IsContinue=*/true, S);
OptLabelTy TargetLabel = std::nullopt;
const VariableScope<Emitter> *ContinueScope = nullptr;
@@ -7245,7 +7245,7 @@ bool Compiler<Emitter>::visitContinueStmt(const ContinueStmt *S) {
// May be null if the named loop is outside of the
// current evaluation context, i.e. not a valid target.
if (!TargetLoop)
- return this->emitUnsupported(S);
+ return this->emitInvalidTargetLabel(/*IsContinue=*/true, S);
for (auto LI : LabelInfoStack) {
if (LI.Name == TargetLoop) {
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 62f179ebaf7b83..2a6ce4b70b9774 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -3721,6 +3721,13 @@ inline bool Unsupported(InterpState &S, CodePtr OpPC) {
return false;
}
+inline bool InvalidTargetLabel(InterpState &S, CodePtr OpPC, bool IsContinue) {
+ const SourceLocation &Loc = S.Current->getLocation(OpPC);
+ S.FFDiag(Loc, diag::note_break_continue_label_outside_context)
+ << S.Current->getRange(OpPC) << IsContinue;
+ return false;
+}
+
inline bool PushIgnoreDiags(InterpState &S) {
++S.DiagIgnoreDepth;
if (S.DiagIgnoreDepth != 1)
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 447fec1f1d2f57..2b7ee12b339488 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -968,6 +968,10 @@ def InvalidShuffleVectorIndex : Opcode {
let Args = [ArgUint32];
}
+def InvalidTargetLabel : Opcode {
+ let Args = [ArgBool];
+}
+
def Assume : Opcode;
def ArrayDecay : Opcode;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index d6927cee293129..9abcaa3836f575 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6392,7 +6392,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// current evaluation context, i.e. not a valid target.
if (!LoopOrSwitch) {
Info.FFDiag(S->getBeginLoc(),
- diag::note_constexpr_stmt_expr_unsupported);
+ diag::note_break_continue_label_outside_context)
+ << isa<ContinueStmt>(B);
return ESR_Failed;
}
}
diff --git a/clang/test/SemaCXX/labeled-break-continue.cpp b/clang/test/SemaCXX/labeled-break-continue.cpp
index 08036d1bb3b3d9..1c827bbfd24af3 100644
--- a/clang/test/SemaCXX/labeled-break-continue.cpp
+++ b/clang/test/SemaCXX/labeled-break-continue.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++20 -verify=expected,no-new-interp -fsyntax-only -fnamed-loops %s -fno-experimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++20 -verify -fsyntax-only -fnamed-loops %s -fno-experimental-new-constant-interpreter
// RUN: %clang_cc1 -std=c++20 -verify -fsyntax-only -fnamed-loops %s -fexperimental-new-constant-interpreter
int a[10]{};
@@ -54,7 +54,7 @@ void f3() {
void f4() {
l1: for (;;) {
constexpr int x = ({ // expected-error {{constexpr variable 'x' must be initialized by a constant expression}}
- break l1; // no-new-interp-note {{not supported in a constant expression}}
+ break l1; // expected-note {{cannot break to a label outside the current evaluation context}}
1;
});
}
@@ -63,7 +63,7 @@ void f4() {
void f5() {
l1: for (;;) {
constexpr int x = ({ // expected-error {{constexpr variable 'x' must be initialized by a constant expression}}
- continue l1; // no-new-interp-note {{not supported in a constant expression}}
+ continue l1; // expected-note {{cannot continue to a label outside the current evaluation context}}
1;
});
}
@@ -72,7 +72,7 @@ void f5() {
void f6() {
l1: for (;;) {
constexpr int x = ({ // expected-error {{constexpr variable 'x' must be initialized by a constant expression}}
- for (;;) break l1; // expected-note {{not supported in a constant expression}}
+ for (;;) break l1; // expected-note {{cannot break to a label outside the current evaluation context}}
1;
});
}
@@ -81,7 +81,7 @@ void f6() {
void f7() {
l1: for (;;) {
constexpr int x = ({ // expected-error {{constexpr variable 'x' must be initialized by a constant expression}}
- for (;;) continue l1; // expected-note {{not supported in a constant expression}}
+ for (;;) continue l1; // expected-note {{cannot continue to a label outside the current evaluation context}}
1;
});
}
>From d1edde73ab42ab68c1b43012eac43b362a090432 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Wed, 14 Oct 2026 02:24:46 +0000
Subject: [PATCH 29/30] Update ReleaseNotes.md
Co-authored-by: Ambrose Leeb <aeternalmail at gmail.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 2c5d6dbfb4b052..d78022dcbbba1e 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` condition.
+ in a statement expression within a `switch` condition. (#GH184060)
#### Miscellaneous Bug Fixes
>From 39ca6987856cb59235ee54a187cdf1aee8b54891 Mon Sep 17 00:00:00 2001
From: Expertcoderz <expertcoderzx at gmail.com>
Date: Wed, 14 Oct 2026 11:32:27 +0000
Subject: [PATCH 30/30] Remove unnecessary variable declaration in Interp.h
Co-authored-by: Timm Baeder <tbaeder at redhat.com>
---
clang/lib/AST/ByteCode/Interp.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 2a6ce4b70b9774..a357963251c8b0 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -3722,8 +3722,7 @@ inline bool Unsupported(InterpState &S, CodePtr OpPC) {
}
inline bool InvalidTargetLabel(InterpState &S, CodePtr OpPC, bool IsContinue) {
- const SourceLocation &Loc = S.Current->getLocation(OpPC);
- S.FFDiag(Loc, diag::note_break_continue_label_outside_context)
+ S.FFDiag(S.Current->getLocation(OpPC), diag::note_break_continue_label_outside_context)
<< S.Current->getRange(OpPC) << IsContinue;
return false;
}
More information about the cfe-commits
mailing list