[clang] [analyzer] Allow SVals as llvm::Immutable{Map, Set} keys (PR #205319)

Balázs Benics via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 23 05:25:12 PDT 2026


https://github.com/steakhal updated https://github.com/llvm/llvm-project/pull/205319

>From b84315d999eed3797d7965ee48ce7ac48678d480 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Tue, 23 Jun 2026 12:28:40 +0100
Subject: [PATCH 1/3] [analyzer] Allow SVals as llvm::Immutable{Map,Set} keys

---
 .../StaticAnalyzer/Core/PathSensitive/SVals.h | 30 +++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index aeb57b28077c6..3c617d9ebd471 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -22,6 +22,7 @@
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ImmutableSet.h"
 #include "llvm/ADT/PointerUnion.h"
 #include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/ADT/iterator_range.h"
@@ -102,6 +103,10 @@ class SVal {
   bool operator==(SVal R) const { return Kind == R.Kind && Data == R.Data; }
   bool operator!=(SVal R) const { return !(*this == R); }
 
+  // Allow implementing traits for SVal to be used as a key in
+  // ImmutableSet / ImmutableMap.
+  friend struct ::llvm::ImutContainerInfo<SVal>;
+
   bool isUnknown() const { return getKind() == UnknownValKind; }
 
   bool isUndef() const { return getKind() == UndefinedValKind; }
@@ -529,6 +534,31 @@ class ConcreteInt : public Loc {
 } // namespace clang
 
 namespace llvm {
+// Allow SVal to be used as a key in ImmutableSet / ImmutableMap.
+template <>
+struct ImutContainerInfo<clang::ento::SVal>
+    : public ImutProfileInfo<clang::ento::SVal> {
+  using value_type = clang::ento::SVal;
+  using value_type_ref = clang::ento::SVal;
+  using key_type = value_type;
+  using key_type_ref = value_type_ref;
+  using data_type = bool;
+  using data_type_ref = bool;
+
+  static key_type_ref KeyOfValue(value_type_ref D) { return D; }
+  static data_type_ref DataOfValue(value_type_ref) { return true; }
+
+  static bool isEqual(clang::ento::SVal L, clang::ento::SVal R) {
+    return L == R;
+  }
+
+  static bool isLess(clang::ento::SVal L, clang::ento::SVal R) {
+    return std::tie(L.Data, L.Kind) < std::tie(R.Data, R.Kind);
+  }
+
+  static bool isDataEqual(data_type_ref, data_type_ref) { return true; }
+};
+
 template <typename To, typename From>
 struct CastInfo<
     To, From,

>From a53966739756696c61f27227a97d1c52a733958d Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Tue, 23 Jun 2026 12:51:03 +0100
Subject: [PATCH 2/3] Delegate isLess to SVal::operator<

---
 .../clang/StaticAnalyzer/Core/PathSensitive/SVals.h   | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 3c617d9ebd471..2db28f6857e17 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -100,13 +100,12 @@ class SVal {
     ID.AddInteger(llvm::to_underlying(getKind()));
   }
 
+  bool operator<(SVal R) const {
+    return std::tie(Data, Kind) < std::tie(R.Data, R.Kind);
+  }
   bool operator==(SVal R) const { return Kind == R.Kind && Data == R.Data; }
   bool operator!=(SVal R) const { return !(*this == R); }
 
-  // Allow implementing traits for SVal to be used as a key in
-  // ImmutableSet / ImmutableMap.
-  friend struct ::llvm::ImutContainerInfo<SVal>;
-
   bool isUnknown() const { return getKind() == UnknownValKind; }
 
   bool isUndef() const { return getKind() == UndefinedValKind; }
@@ -552,9 +551,7 @@ struct ImutContainerInfo<clang::ento::SVal>
     return L == R;
   }
 
-  static bool isLess(clang::ento::SVal L, clang::ento::SVal R) {
-    return std::tie(L.Data, L.Kind) < std::tie(R.Data, R.Kind);
-  }
+  static bool isLess(clang::ento::SVal L, clang::ento::SVal R) { return L < R; }
 
   static bool isDataEqual(data_type_ref, data_type_ref) { return true; }
 };

>From 874d6af0d0f54b1ce78b42199d8fd1b8face8019 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Tue, 23 Jun 2026 12:52:11 +0100
Subject: [PATCH 3/3] Use std::tie and swap fields to match declaration order

---
 clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 2db28f6857e17..0561a2b8d1d77 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -103,7 +103,9 @@ class SVal {
   bool operator<(SVal R) const {
     return std::tie(Data, Kind) < std::tie(R.Data, R.Kind);
   }
-  bool operator==(SVal R) const { return Kind == R.Kind && Data == R.Data; }
+  bool operator==(SVal R) const {
+    return std::tie(Data, Kind) == std::tie(R.Data, R.Kind);
+  }
   bool operator!=(SVal R) const { return !(*this == R); }
 
   bool isUnknown() const { return getKind() == UnknownValKind; }



More information about the cfe-commits mailing list