[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