Marius =?utf-8?q?Dörner?= <[email protected]> Message-ID: In-Reply-To: <llvm.org/llvm/llvm-project/pull/[email protected]>
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?= <[email protected]> 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?= <[email protected]> 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}} } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
