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

Reply via email to