[clang] [clang][bytecode] Implement case ranges (PR #168418)
marius doerner via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 18 11:06:29 PST 2025
Marius =?utf-8?q?Dörner?= <marius.doerner1 at icloud.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/168418 at github.com>
https://github.com/mariusdr updated https://github.com/llvm/llvm-project/pull/168418
>From 8fdecfa129927fd6d120f419251832c746fc6467 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marius=20D=C3=B6rner?= <marius.doerner1 at icloud.com>
Date: Mon, 17 Nov 2025 19:08:21 +0100
Subject: [PATCH 1/2] [Clang][ByteCode] Implement case ranges
Implement GNU case ranges for constexpr bytecode interpreter.
Closes #165969
---
clang/lib/AST/ByteCode/Compiler.cpp | 33 ++++++++++++--
clang/test/AST/ByteCode/switch.cpp | 68 +++++++++++++++++++++++++++++
2 files changed, 98 insertions(+), 3 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index f8bbfed8bb387..f52f6e396bb47 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -6016,11 +6016,38 @@ bool Compiler<Emitter>::visitSwitchStmt(const SwitchStmt *S) {
for (const SwitchCase *SC = S->getSwitchCaseList(); SC;
SC = SC->getNextSwitchCase()) {
if (const auto *CS = dyn_cast<CaseStmt>(SC)) {
- // FIXME: Implement ranges.
- if (CS->caseStmtIsGNURange())
- return false;
CaseLabels[SC] = this->getLabel();
+ if (CS->caseStmtIsGNURange()) {
+ LabelTy EndOfRangeCheck = this->getLabel();
+ const Expr *Low = CS->getLHS();
+ const Expr *High = CS->getRHS();
+ if (Low->isValueDependent() || High->isValueDependent())
+ return false;
+
+ if (!this->emitGetLocal(CondT, CondVar, CS))
+ return false;
+ if (!this->visit(Low))
+ return false;
+ PrimType LT = this->classifyPrim(Low->getType());
+ if (!this->emitGE(LT, S))
+ return false;
+ if (!this->jumpFalse(EndOfRangeCheck))
+ return false;
+
+ if (!this->emitGetLocal(CondT, CondVar, CS))
+ return false;
+ if (!this->visit(High))
+ return false;
+ PrimType HT = this->classifyPrim(High->getType());
+ if (!this->emitLE(HT, S))
+ return false;
+ if (!this->jumpTrue(CaseLabels[CS]))
+ return false;
+ this->emitLabel(EndOfRangeCheck);
+ continue;
+ }
+
const Expr *Value = CS->getLHS();
if (Value->isValueDependent())
return false;
diff --git a/clang/test/AST/ByteCode/switch.cpp b/clang/test/AST/ByteCode/switch.cpp
index 8136f92f5dfd3..39b949950f22b 100644
--- a/clang/test/AST/ByteCode/switch.cpp
+++ b/clang/test/AST/ByteCode/switch.cpp
@@ -86,3 +86,71 @@ constexpr int another_test(int val) { // both-note {{declared here}}
}
static_assert(another_test(1) == 100, ""); // both-error {{static assertion failed}} \
// both-note {{evaluates to}}
+
+namespace gnurange {
+constexpr int l(int n) {
+ return n + 1;
+}
+constexpr int h(int n) {
+ return 2 * n + 1;
+}
+constexpr int f(int x) {
+ const int n = 2;
+ constexpr struct {
+ char lo {'a'};
+ char hi {'z'};
+ } s;
+
+ switch (x) {
+ case l(n) ... h(n):
+ return 1;
+ case -1 ... 1:
+ return 2;
+ case 9 ... 14:
+ return 3;
+ case 15:
+ return 4;
+ case 16 ... 20:
+ return 5;
+ case s.lo ... s.hi:
+ return 6;
+ default:
+ return -1;
+ }
+}
+static_assert(f(0) == 2);
+static_assert(f(2) == -1);
+static_assert(f(3) == 1);
+static_assert(f(4) == 1);
+static_assert(f(5) == 1);
+static_assert(f(6) == -1);
+static_assert(f(14) == 3);
+static_assert(f(15) == 4);
+static_assert(f(16) == 5);
+static_assert(f(20) == 5);
+static_assert(f('d') == 6);
+
+template <int Lo, int Hi>
+constexpr bool g(int x) {
+ switch (x) {
+ case Lo ... Hi:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+static_assert(g<100, 200>(132));
+
+constexpr bool j(int x) { // both-note {{declared here}}
+ switch (x) {
+ case bad(x) ... 100: // both-error {{case value is not a constant expression}} \
+ // both-note {{cannot be used in a constant expression}}
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+static_assert(j(1)); // both-error {{static assertion failed}}
+}
>From baa4fd70b3af2b56cb35a88ee5b1b0c63cc4a34e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marius=20D=C3=B6rner?= <marius.doerner1 at icloud.com>
Date: Tue, 18 Nov 2025 20:05:06 +0100
Subject: [PATCH 2/2] additional test cases
---
clang/test/AST/ByteCode/switch.cpp | 159 ++++++++++++++++++-----------
1 file changed, 97 insertions(+), 62 deletions(-)
diff --git a/clang/test/AST/ByteCode/switch.cpp b/clang/test/AST/ByteCode/switch.cpp
index 39b949950f22b..151b4a5852e88 100644
--- a/clang/test/AST/ByteCode/switch.cpp
+++ b/clang/test/AST/ByteCode/switch.cpp
@@ -88,69 +88,104 @@ static_assert(another_test(1) == 100, ""); // both-error {{static assertion fail
// both-note {{evaluates to}}
namespace gnurange {
-constexpr int l(int n) {
- return n + 1;
-}
-constexpr int h(int n) {
- return 2 * n + 1;
-}
-constexpr int f(int x) {
- const int n = 2;
- constexpr struct {
- char lo {'a'};
- char hi {'z'};
- } s;
-
- switch (x) {
- case l(n) ... h(n):
- return 1;
- case -1 ... 1:
- return 2;
- case 9 ... 14:
- return 3;
- case 15:
- return 4;
- case 16 ... 20:
- return 5;
- case s.lo ... s.hi:
- return 6;
- default:
- return -1;
+ constexpr int l(int n) {
+ return n + 1;
}
-}
-static_assert(f(0) == 2);
-static_assert(f(2) == -1);
-static_assert(f(3) == 1);
-static_assert(f(4) == 1);
-static_assert(f(5) == 1);
-static_assert(f(6) == -1);
-static_assert(f(14) == 3);
-static_assert(f(15) == 4);
-static_assert(f(16) == 5);
-static_assert(f(20) == 5);
-static_assert(f('d') == 6);
-
-template <int Lo, int Hi>
-constexpr bool g(int x) {
- switch (x) {
- case Lo ... Hi:
- break;
- default:
- return false;
+ constexpr int h(int n) {
+ return 2 * n + 1;
}
- return true;
-}
-static_assert(g<100, 200>(132));
-
-constexpr bool j(int x) { // both-note {{declared here}}
- switch (x) {
- case bad(x) ... 100: // both-error {{case value is not a constant expression}} \
- // both-note {{cannot be used in a constant expression}}
- return true;
- default:
- break;
+ constexpr int f(int x) {
+ const int n = 2;
+ constexpr struct {
+ char lo {'a'};
+ char hi {'z'};
+ } s;
+
+ switch (x) {
+ case l(n) ... h(n):
+ return 1;
+ case -1 ... 1:
+ return 2;
+ case 9 ... 14:
+ return 3;
+ case 15:
+ return 4;
+ case 16 ... 20:
+ return 5;
+ case s.lo ... s.hi:
+ return 6;
+ default:
+ return -1;
+ }
}
- return false;
-}
-static_assert(j(1)); // both-error {{static assertion failed}}
+ static_assert(f(0) == 2);
+ static_assert(f(2) == -1);
+ static_assert(f(3) == 1);
+ static_assert(f(4) == 1);
+ static_assert(f(5) == 1);
+ static_assert(f(6) == -1);
+ static_assert(f(14) == 3);
+ static_assert(f(15) == 4);
+ static_assert(f(16) == 5);
+ static_assert(f(20) == 5);
+ static_assert(f('d') == 6);
+
+ template <int Lo, int Hi>
+ constexpr bool g(int x) {
+ switch (x) {
+ case Lo ... Hi:
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+ static_assert(g<100, 200>(132));
+
+ constexpr bool m(int x) {
+ switch (x) {
+ case 10 ... 1: // both-warning {{empty case range specified}}
+ return true;
+ default:
+ return false;
+ }
+ }
+ static_assert(m(3)); // both-error {{static assertion failed due to requirement 'm(3)'}}
+ static_assert(!m(3));
+
+ constexpr bool j(int x) { // both-note {{declared here}}
+ switch (x) {
+ case bad(x) ... 100: // both-error {{case value is not a constant expression}} \
+ // both-note {{cannot be used in a constant expression}}
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+ static_assert(j(1)); // both-error {{static assertion failed}}
+
+ constexpr bool d(int x) { // both-note {{declared here}}
+ switch (x) {
+ case -100 ... bad(x): // both-error {{case value is not a constant expression}} \
+ // both-note {{cannot be used in a constant expression}}
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+ static_assert(d(1)); // both-error {{static assertion failed}}
+
+ constexpr bool s(int x) { // both-note {{declared here}}
+ switch (x) {
+ case bad(x) - 100 ... bad(x) + 100: // both-error {{case value is not a constant expression}} \
+ // both-note {{cannot be used in a constant expression}}
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+ static_assert(s(1)); // both-error {{static assertion failed}}
}
More information about the cfe-commits
mailing list