Skip to content

Conversation

kuhar
Copy link
Member

@kuhar kuhar commented Oct 13, 2025

Prior to this patch, .Cases and .CasesLower were not variadic functions and accepted a fixed number of arguments: up to 10 for the former and up to 5 for the latter.
This is close to unfixable with variadic templates because of the following constraints:

  • There would be a variadic number of cases and the single value would be at the very end. For a parameter pack approach to work, we would want the value to be the head and the cases strings to follow, but rotating a parameter pack is quite awkward and requires heavy template metaprogramming.
  • Even if we did rotate the parameter pack, the existing function signature forces conversion of cases to StringLiteral and the value to T. This is hard to achieve with variadic templates because we can't specify that all cases must be of type StringLiteral, and doing the conversion later won't work because of the attribute enable_if in StringLiteral's constructor that doesn't work on non-literal character arrays.
  • Refactoring all the existing code to put the value first is very intrusive and bugprone when the value parameter is also a string literal.

Instead, generalize .Cases and .CasesLower and make the code manageable by taking an initializer list. The added benefit is that this clearly delineates where case strings end and where the value begins, which can be hard to tell when the value parameter is also a string literal.

I plan to eventually deprecate the manually-enumerated overloads of .Cases. and .CasesLower.

@llvmbot
Copy link
Member

llvmbot commented Oct 13, 2025

@llvm/pr-subscribers-llvm-adt

Author: Jakub Kuderski (kuhar)

Changes

Prior to this patch, .Cases and .CasesLower were not variadic functions and accepted a fixed number of arguments: up to 10 for the former and up to 5 for the latter.
This is close to unfixable with variadic templates because of the following constraints:

  • There would be a variadic number of cases and the single value would be at the very end. For a parameter pack approach to work, we would want the value to be the head and the cases strings to follow, but rotating a parameter pack is quite awkward and requires heavy template metaprogramming.
  • Even if we did rotate the parameter pack, the existing function signature forces conversion of cases to StringLiteral and the value to T. This is hard to achieve with variadic templates because we can't specify that all cases must be of type StringLiteral, and doing the conversion later won't work because of the attribute enable_if in StringLiteral's constructor that doesn't work on non-literal character arrays.
  • Refactoring all the existing code to put the value first is very intrusive and bugprone when the value parameter is also a string literal.

Instead, Generalize .Cases and .CasesLower and make the code manageable by taking an initializer list. The added benefit is that this clearly delineates where case strings end and where the value begins, which can be hard to tell when the value parameter is also a string literal.

I plan to eventually deprecate the manually-enumerate overloads of .Cases. and .CasesLower.


Full diff: https://github.com/llvm/llvm-project/pull/163117.diff

2 Files Affected:

  • (modified) llvm/include/llvm/ADT/StringSwitch.h (+34-18)
  • (modified) llvm/unittests/ADT/StringSwitchTest.cpp (+11-2)
diff --git a/llvm/include/llvm/ADT/StringSwitch.h b/llvm/include/llvm/ADT/StringSwitch.h
index 0ce7c57a358f2..a96535cd077fd 100644
--- a/llvm/include/llvm/ADT/StringSwitch.h
+++ b/llvm/include/llvm/ADT/StringSwitch.h
@@ -17,6 +17,7 @@
 #include "llvm/Support/ErrorHandling.h"
 #include <cassert>
 #include <cstring>
+#include <initializer_list>
 #include <optional>
 
 namespace llvm {
@@ -85,55 +86,60 @@ class StringSwitch {
     return *this;
   }
 
+  StringSwitch &Cases(std::initializer_list<StringLiteral> CaseStrings,
+                      T Value) {
+    return CasesImpl(Value, CaseStrings);
+  }
+
   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, T Value) {
-    return CasesImpl(Value, S0, S1);
+    return CasesImpl(Value, {S0, S1});
   }
 
   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
                       T Value) {
-    return CasesImpl(Value, S0, S1, S2);
+    return CasesImpl(Value, {S0, S1, S2});
   }
 
   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
                       StringLiteral S3, T Value) {
-    return CasesImpl(Value, S0, S1, S2, S3);
+    return CasesImpl(Value, {S0, S1, S2, S3});
   }
 
   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
                       StringLiteral S3, StringLiteral S4, T Value) {
-    return CasesImpl(Value, S0, S1, S2, S3, S4);
+    return CasesImpl(Value, {S0, S1, S2, S3, S4});
   }
 
   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
                       T Value) {
-    return CasesImpl(Value, S0, S1, S2, S3, S4, S5);
+    return CasesImpl(Value, {S0, S1, S2, S3, S4, S5});
   }
 
   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
                       StringLiteral S6, T Value) {
-    return CasesImpl(Value, S0, S1, S2, S3, S4, S5, S6);
+    return CasesImpl(Value, {S0, S1, S2, S3, S4, S5, S6});
   }
 
   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
                       StringLiteral S6, StringLiteral S7, T Value) {
-    return CasesImpl(Value, S0, S1, S2, S3, S4, S5, S6, S7);
+    return CasesImpl(Value, {S0, S1, S2, S3, S4, S5, S6, S7});
   }
 
   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
                       StringLiteral S6, StringLiteral S7, StringLiteral S8,
                       T Value) {
-    return CasesImpl(Value, S0, S1, S2, S3, S4, S5, S6, S7, S8);
+    return CasesImpl(Value, {S0, S1, S2, S3, S4, S5, S6, S7, S8});
   }
 
   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
                       StringLiteral S6, StringLiteral S7, StringLiteral S8,
                       StringLiteral S9, T Value) {
-    return CasesImpl(Value, S0, S1, S2, S3, S4, S5, S6, S7, S8, S9);
+    return CasesImpl(Value, {S0, S1, S2, S3, S4, S5, S6, S7, S8, S9});
   }
 
   // Case-insensitive case matchers.
@@ -156,23 +162,28 @@ class StringSwitch {
     return *this;
   }
 
+  StringSwitch &CasesLower(std::initializer_list<StringLiteral> CaseStrings,
+                           T Value) {
+    return CasesLowerImpl(Value, CaseStrings);
+  }
+
   StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, T Value) {
-    return CasesLowerImpl(Value, S0, S1);
+    return CasesLowerImpl(Value, {S0, S1});
   }
 
   StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
                            T Value) {
-    return CasesLowerImpl(Value, S0, S1, S2);
+    return CasesLowerImpl(Value, {S0, S1, S2});
   }
 
   StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
                            StringLiteral S3, T Value) {
-    return CasesLowerImpl(Value, S0, S1, S2, S3);
+    return CasesLowerImpl(Value, {S0, S1, S2, S3});
   }
 
   StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
                            StringLiteral S3, StringLiteral S4, T Value) {
-    return CasesLowerImpl(Value, S0, S1, S2, S3, S4);
+    return CasesLowerImpl(Value, {S0, S1, S2, S3, S4});
   }
 
   [[nodiscard]] R Default(T Value) {
@@ -211,16 +222,21 @@ class StringSwitch {
     return false;
   }
 
-  template <typename... Args> StringSwitch &CasesImpl(T &Value, Args... Cases) {
+  StringSwitch &CasesImpl(T &Value,
+                          std::initializer_list<StringLiteral> Cases) {
     // Stop matching after the string is found.
-    (... || CaseImpl(Value, Cases));
+    for (StringLiteral S : Cases)
+      if (CaseImpl(Value, S))
+        break;
     return *this;
   }
 
-  template <typename... Args>
-  StringSwitch &CasesLowerImpl(T &Value, Args... Cases) {
+  StringSwitch &CasesLowerImpl(T &Value,
+                               std::initializer_list<StringLiteral> Cases) {
     // Stop matching after the string is found.
-    (... || CaseLowerImpl(Value, Cases));
+    for (StringLiteral S : Cases)
+      if (CaseLowerImpl(Value, S))
+        break;
     return *this;
   }
 };
diff --git a/llvm/unittests/ADT/StringSwitchTest.cpp b/llvm/unittests/ADT/StringSwitchTest.cpp
index bcb1521baa287..0fbf37153593e 100644
--- a/llvm/unittests/ADT/StringSwitchTest.cpp
+++ b/llvm/unittests/ADT/StringSwitchTest.cpp
@@ -153,13 +153,14 @@ TEST(StringSwitchTest, EndsWithLower) {
 }
 
 TEST(StringSwitchTest, Cases) {
-  enum class OSType { Windows, Linux, Unknown };
+  enum class OSType { Windows, Linux, MacOS, Unknown };
 
   auto Translate = [](StringRef S) {
     return llvm::StringSwitch<OSType>(S)
         .Cases(StringLiteral::withInnerNUL("wind\0ws"), "win32", "winnt",
                OSType::Windows)
         .Cases("linux", "unix", "*nix", "posix", OSType::Linux)
+        .Cases({"macos", "osx"}, OSType::MacOS)
         .Default(OSType::Unknown);
   };
 
@@ -172,21 +173,26 @@ TEST(StringSwitchTest, Cases) {
   EXPECT_EQ(OSType::Linux, Translate("*nix"));
   EXPECT_EQ(OSType::Linux, Translate("posix"));
 
+  EXPECT_EQ(OSType::MacOS, Translate("macos"));
+  EXPECT_EQ(OSType::MacOS, Translate("osx"));
+
   // Note that the whole null-terminator embedded string is required for the
   // case to match.
   EXPECT_EQ(OSType::Unknown, Translate("wind"));
   EXPECT_EQ(OSType::Unknown, Translate("Windows"));
+  EXPECT_EQ(OSType::Unknown, Translate("MacOS"));
   EXPECT_EQ(OSType::Unknown, Translate(""));
 }
 
 TEST(StringSwitchTest, CasesLower) {
-  enum class OSType { Windows, Linux, Unknown };
+  enum class OSType { Windows, Linux, MacOS, Unknown };
 
   auto Translate = [](StringRef S) {
     return llvm::StringSwitch<OSType>(S)
         .CasesLower(StringLiteral::withInnerNUL("wind\0ws"), "win32", "winnt",
                     OSType::Windows)
         .CasesLower("linux", "unix", "*nix", "posix", OSType::Linux)
+        .CasesLower({"macos", "osx"}, OSType::MacOS)
         .Default(OSType::Unknown);
   };
 
@@ -202,6 +208,9 @@ TEST(StringSwitchTest, CasesLower) {
   EXPECT_EQ(OSType::Windows, Translate(llvm::StringRef("wind\0ws", 7)));
   EXPECT_EQ(OSType::Linux, Translate("linux"));
 
+  EXPECT_EQ(OSType::MacOS, Translate("macOS"));
+  EXPECT_EQ(OSType::MacOS, Translate("OSX"));
+
   EXPECT_EQ(OSType::Unknown, Translate("wind"));
   EXPECT_EQ(OSType::Unknown, Translate(""));
 }

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kuhar kuhar merged commit 8642762 into llvm:main Oct 13, 2025
12 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 13, 2025

LLVM Buildbot has detected a new failure on builder clang-m68k-linux-cross running on suse-gary-m68k-cross while building llvm at step 5 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/27/builds/17431

Here is the relevant piece of the build log for the reference
Step 5 (ninja check 1) failure: stage 1 checked (failure)
...
[171/890] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/tweaks/SwapIfBranchesTests.cpp.o
[172/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Parse/ParseHLSLRootSignatureTest.cpp.o
[173/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/ArenaTest.cpp.o
[174/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/FormulaTest.cpp.o
[175/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/DataflowAnalysisContextTest.cpp.o
[176/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Driver/ToolChainTest.cpp.o
[177/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/CloneDetectionTest.cpp.o
[178/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/ValueTest.cpp.o
[179/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/MacroExpansionContextTest.cpp.o
[180/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/IntervalPartitionTest.cpp.o
FAILED: tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/IntervalPartitionTest.cpp.o 
/usr/bin/c++ -DGTEST_HAS_RTTI=0 -DLLVM_BUILD_STATIC -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/tools/clang/unittests -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/tools/clang/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/Tooling -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/third-party/unittest/googletest/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/third-party/unittest/googlemock/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wno-missing-field-initializers -pedantic -Wno-long-long -Wimplicit-fallthrough -Wno-uninitialized -Wno-nonnull -Wno-class-memaccess -Wno-dangling-reference -Wno-redundant-move -Wno-pessimizing-move -Wno-array-bounds -Wno-stringop-overread -Wno-noexcept-type -Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment -Wno-misleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -O3 -DNDEBUG -std=c++17  -Wno-variadic-macros -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -Wno-suggest-override -MD -MT tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/IntervalPartitionTest.cpp.o -MF tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/IntervalPartitionTest.cpp.o.d -o tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/IntervalPartitionTest.cpp.o -c /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/Analysis/IntervalPartitionTest.cpp
c++: fatal error: Killed signal terminated program cc1plus
compilation terminated.
[181/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/APSIntTypeTest.cpp.o
[182/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/AnalyzerOptionsTest.cpp.o
[183/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/DeterminismTest.cpp.o
[184/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp.o
[185/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/CachedConstAccessorsLatticeTest.cpp.o
[186/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/MapLatticeTest.cpp.o
[187/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/MatchSwitchTest.cpp.o
[188/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/CFGMatchSwitchTest.cpp.o
[189/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/TestingSupport.cpp.o
[190/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/LoggerTest.cpp.o
[191/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/RecordOpsTest.cpp.o
[192/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/SimplifyConstraintsTest.cpp.o
[193/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/CFGDominatorTree.cpp.o
[194/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/CFGTest.cpp.o
[195/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/DebugSupportTest.cpp.o
[196/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/CallEventTest.cpp.o
[197/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/TransferBranchTest.cpp.o
[198/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/TestingSupportTest.cpp.o
[199/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/BlockEntranceCallbackTest.cpp.o
[200/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/LifetimeSafetyTest.cpp.o
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/Analysis/LifetimeSafetyTest.cpp: In instantiation of ‘bool clang::lifetimes::internal::{anonymous}::AreLiveAtImplMatcherP2<Annotation_type, ConfFilter_type>::gmock_Impl<arg_type>::MatchAndExplain(const arg_type&, testing::MatchResultListener*) const [with arg_type = const clang::lifetimes::internal::{anonymous}::OriginsInfo&; Annotation_type = const char*; ConfFilter_type = clang::lifetimes::internal::{anonymous}::LivenessKindFilter]’:
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/Analysis/LifetimeSafetyTest.cpp:259:1:   required from here
  259 | MATCHER_P2(AreLiveAtImpl, Annotation, ConfFilter, "") {
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/Analysis/LifetimeSafetyTest.cpp:269:19: warning: loop variable ‘<structured bindings>’ creates a copy from type ‘const std::pair<clang::lifetimes::internal::utils::ID<clang::lifetimes::internal::OriginTag>, clang::lifetimes::internal::LivenessKind>’ [-Wrange-loop-construct]
  269 |   for (const auto [OID, ActualConfidence] : ActualLiveSetOpt.value()) {
      |                   ^~~~~~~~~~~~~~~~~~~~~~~
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/Analysis/LifetimeSafetyTest.cpp:269:19: note: use reference type to prevent copying
  269 |   for (const auto [OID, ActualConfidence] : ActualLiveSetOpt.value()) {
      |                   ^~~~~~~~~~~~~~~~~~~~~~~
      |                   &
[201/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/SignAnalysisTest.cpp.o
[202/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/SingleVarConstantPropagationTest.cpp.o
[203/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp.o
[204/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/MultiVarConstantPropagationTest.cpp.o
[205/890] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/ASTOpsTest.cpp.o

akadutta pushed a commit to akadutta/llvm-project that referenced this pull request Oct 14, 2025
Prior to this patch, `.Cases` and `.CasesLower` were **not** variadic
functions and accepted a fixed number of arguments: up to 10 for the
former and up to 5 for the latter.
This is close to unfixable with variadic templates because of the
following constraints:
* There would be a variadic number of cases and the single value would
be at the very end. For a parameter pack approach to work, we would want
the value to be the head and the cases strings to follow, but rotating a
parameter pack is quite awkward and requires heavy template
metaprogramming.
* Even if we did rotate the parameter pack, the existing function
signature forces conversion of cases to `StringLiteral` and the value to
`T`. This is hard to achieve with variadic templates because we can't
specify that all cases must be of type `StringLiteral`, and doing the
conversion later won't work because of the attribute enable_if in
`StringLiteral`'s constructor that doesn't work on non-literal character
arrays.
* Refactoring all the existing code to put the value first is very
intrusive and bugprone when the value parameter is also a string
literal.
 
Instead, generalize `.Cases` and `.CasesLower` and make the code
manageable by taking an initializer list. The added benefit is that this
clearly delineates where case strings end and where the value begins,
which can be hard to tell when the value parameter is also a string
literal.

I plan to eventually deprecate the manually-enumerated overloads of
`.Cases.` and `.CasesLower`.
kuhar added a commit that referenced this pull request Oct 15, 2025
…163405)

Switch to the `.Cases({S0, S1, ...}, Value)` overload instead.

Update existing uses affected by the deprecation and the surrounding
code (for consistency).

This is a part of a larger cleanup of StringSwitch. The goal is to
eventually deprecate all manually-enumerated overloads of Cases with a
hardcoded number of case values (in favor of passing them via an
initializer list). You can find the full explanation here:
#163117.

Start small (6+ arguments) to keep the number of changes manageable.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Oct 15, 2025
…ted. NFC. (#163405)

Switch to the `.Cases({S0, S1, ...}, Value)` overload instead.

Update existing uses affected by the deprecation and the surrounding
code (for consistency).

This is a part of a larger cleanup of StringSwitch. The goal is to
eventually deprecate all manually-enumerated overloads of Cases with a
hardcoded number of case values (in favor of passing them via an
initializer list). You can find the full explanation here:
llvm/llvm-project#163117.

Start small (6+ arguments) to keep the number of changes manageable.
kuhar added a commit to kuhar/llvm-project that referenced this pull request Oct 20, 2025
Suggest the `initializer_list` overload instead.

4+ args is an arbitrary number that allows for incremental deprecation
without having too update too many call sites.

For more context, see llvm#163117.
kuhar added a commit that referenced this pull request Oct 20, 2025
Suggest the `initializer_list` overload instead.

4+ args is an arbitrary number that allows for incremental deprecation
without having too update too many call sites.

For more context, see #163117.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Oct 20, 2025
…4276)

Suggest the `initializer_list` overload instead.

4+ args is an arbitrary number that allows for incremental deprecation
without having too update too many call sites.

For more context, see llvm/llvm-project#163117.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants