Skip to content

Commit ca09020

Browse files
jyknightmahesh-attarde
authored andcommitted
Reject out-of-bounds enum sentinels in DenseMap/DenseSet. (llvm#150308)
This makes the bug in PR llvm#125556 which was fixed by dc87a14 into a compile-time error. ...and fix a newly-discovered instance of this issue, triggered by a `llvm::MapVector<AccessSpecifier, ...>` in clang-tools-extra/clangd/refactor/tweaks/OverridePureVirtuals.cpp.
1 parent 76025b4 commit ca09020

File tree

2 files changed

+52
-36
lines changed

2 files changed

+52
-36
lines changed

clang/include/clang/Basic/Specifiers.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ namespace clang {
120120

121121
/// A C++ access specifier (public, private, protected), plus the
122122
/// special value "none" which means different things in different contexts.
123-
enum AccessSpecifier {
123+
enum AccessSpecifier : uint8_t {
124124
AS_public,
125125
AS_protected,
126126
AS_private,

llvm/include/llvm/ADT/DenseMapInfo.h

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ inline unsigned combineHashValue(unsigned a, unsigned b) {
5151
/// just be `void`.
5252
template<typename T, typename Enable = void>
5353
struct DenseMapInfo {
54-
//static inline T getEmptyKey();
55-
//static inline T getTombstoneKey();
56-
//static unsigned getHashValue(const T &Val);
57-
//static bool isEqual(const T &LHS, const T &RHS);
54+
// static constexpr T getEmptyKey();
55+
// static constexpr T getTombstoneKey();
56+
// static unsigned getHashValue(const T &Val);
57+
// static bool isEqual(const T &LHS, const T &RHS);
5858
};
5959

6060
// Provide DenseMapInfo for all pointers. Come up with sentinel pointer values
@@ -70,13 +70,13 @@ struct DenseMapInfo<T*> {
7070
// "Log2MaxAlign bits of alignment");
7171
static constexpr uintptr_t Log2MaxAlign = 12;
7272

73-
static inline T* getEmptyKey() {
73+
static constexpr T *getEmptyKey() {
7474
uintptr_t Val = static_cast<uintptr_t>(-1);
7575
Val <<= Log2MaxAlign;
7676
return reinterpret_cast<T*>(Val);
7777
}
7878

79-
static inline T* getTombstoneKey() {
79+
static constexpr T *getTombstoneKey() {
8080
uintptr_t Val = static_cast<uintptr_t>(-2);
8181
Val <<= Log2MaxAlign;
8282
return reinterpret_cast<T*>(Val);
@@ -92,8 +92,8 @@ struct DenseMapInfo<T*> {
9292

9393
// Provide DenseMapInfo for chars.
9494
template<> struct DenseMapInfo<char> {
95-
static inline char getEmptyKey() { return ~0; }
96-
static inline char getTombstoneKey() { return ~0 - 1; }
95+
static constexpr char getEmptyKey() { return ~0; }
96+
static constexpr char getTombstoneKey() { return ~0 - 1; }
9797
static unsigned getHashValue(const char& Val) { return Val * 37U; }
9898

9999
static bool isEqual(const char &LHS, const char &RHS) {
@@ -103,8 +103,8 @@ template<> struct DenseMapInfo<char> {
103103

104104
// Provide DenseMapInfo for unsigned chars.
105105
template <> struct DenseMapInfo<unsigned char> {
106-
static inline unsigned char getEmptyKey() { return ~0; }
107-
static inline unsigned char getTombstoneKey() { return ~0 - 1; }
106+
static constexpr unsigned char getEmptyKey() { return ~0; }
107+
static constexpr unsigned char getTombstoneKey() { return ~0 - 1; }
108108
static unsigned getHashValue(const unsigned char &Val) { return Val * 37U; }
109109

110110
static bool isEqual(const unsigned char &LHS, const unsigned char &RHS) {
@@ -114,8 +114,8 @@ template <> struct DenseMapInfo<unsigned char> {
114114

115115
// Provide DenseMapInfo for unsigned shorts.
116116
template <> struct DenseMapInfo<unsigned short> {
117-
static inline unsigned short getEmptyKey() { return 0xFFFF; }
118-
static inline unsigned short getTombstoneKey() { return 0xFFFF - 1; }
117+
static constexpr unsigned short getEmptyKey() { return 0xFFFF; }
118+
static constexpr unsigned short getTombstoneKey() { return 0xFFFF - 1; }
119119
static unsigned getHashValue(const unsigned short &Val) { return Val * 37U; }
120120

121121
static bool isEqual(const unsigned short &LHS, const unsigned short &RHS) {
@@ -125,8 +125,8 @@ template <> struct DenseMapInfo<unsigned short> {
125125

126126
// Provide DenseMapInfo for unsigned ints.
127127
template<> struct DenseMapInfo<unsigned> {
128-
static inline unsigned getEmptyKey() { return ~0U; }
129-
static inline unsigned getTombstoneKey() { return ~0U - 1; }
128+
static constexpr unsigned getEmptyKey() { return ~0U; }
129+
static constexpr unsigned getTombstoneKey() { return ~0U - 1; }
130130
static unsigned getHashValue(const unsigned& Val) { return Val * 37U; }
131131

132132
static bool isEqual(const unsigned& LHS, const unsigned& RHS) {
@@ -136,8 +136,8 @@ template<> struct DenseMapInfo<unsigned> {
136136

137137
// Provide DenseMapInfo for unsigned longs.
138138
template<> struct DenseMapInfo<unsigned long> {
139-
static inline unsigned long getEmptyKey() { return ~0UL; }
140-
static inline unsigned long getTombstoneKey() { return ~0UL - 1L; }
139+
static constexpr unsigned long getEmptyKey() { return ~0UL; }
140+
static constexpr unsigned long getTombstoneKey() { return ~0UL - 1L; }
141141

142142
static unsigned getHashValue(const unsigned long& Val) {
143143
if constexpr (sizeof(Val) == 4)
@@ -153,8 +153,8 @@ template<> struct DenseMapInfo<unsigned long> {
153153

154154
// Provide DenseMapInfo for unsigned long longs.
155155
template<> struct DenseMapInfo<unsigned long long> {
156-
static inline unsigned long long getEmptyKey() { return ~0ULL; }
157-
static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; }
156+
static constexpr unsigned long long getEmptyKey() { return ~0ULL; }
157+
static constexpr unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; }
158158

159159
static unsigned getHashValue(const unsigned long long& Val) {
160160
return densemap::detail::mix(Val);
@@ -168,16 +168,16 @@ template<> struct DenseMapInfo<unsigned long long> {
168168

169169
// Provide DenseMapInfo for shorts.
170170
template <> struct DenseMapInfo<short> {
171-
static inline short getEmptyKey() { return 0x7FFF; }
172-
static inline short getTombstoneKey() { return -0x7FFF - 1; }
171+
static constexpr short getEmptyKey() { return 0x7FFF; }
172+
static constexpr short getTombstoneKey() { return -0x7FFF - 1; }
173173
static unsigned getHashValue(const short &Val) { return Val * 37U; }
174174
static bool isEqual(const short &LHS, const short &RHS) { return LHS == RHS; }
175175
};
176176

177177
// Provide DenseMapInfo for ints.
178178
template<> struct DenseMapInfo<int> {
179-
static inline int getEmptyKey() { return 0x7fffffff; }
180-
static inline int getTombstoneKey() { return -0x7fffffff - 1; }
179+
static constexpr int getEmptyKey() { return 0x7fffffff; }
180+
static constexpr int getTombstoneKey() { return -0x7fffffff - 1; }
181181
static unsigned getHashValue(const int& Val) { return (unsigned)(Val * 37U); }
182182

183183
static bool isEqual(const int& LHS, const int& RHS) {
@@ -187,11 +187,11 @@ template<> struct DenseMapInfo<int> {
187187

188188
// Provide DenseMapInfo for longs.
189189
template<> struct DenseMapInfo<long> {
190-
static inline long getEmptyKey() {
190+
static constexpr long getEmptyKey() {
191191
return (1UL << (sizeof(long) * 8 - 1)) - 1UL;
192192
}
193193

194-
static inline long getTombstoneKey() { return getEmptyKey() - 1L; }
194+
static constexpr long getTombstoneKey() { return getEmptyKey() - 1L; }
195195

196196
static unsigned getHashValue(const long& Val) {
197197
return (unsigned)(Val * 37UL);
@@ -204,8 +204,10 @@ template<> struct DenseMapInfo<long> {
204204

205205
// Provide DenseMapInfo for long longs.
206206
template<> struct DenseMapInfo<long long> {
207-
static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; }
208-
static inline long long getTombstoneKey() { return -0x7fffffffffffffffLL-1; }
207+
static constexpr long long getEmptyKey() { return 0x7fffffffffffffffLL; }
208+
static constexpr long long getTombstoneKey() {
209+
return -0x7fffffffffffffffLL - 1;
210+
}
209211

210212
static unsigned getHashValue(const long long& Val) {
211213
return (unsigned)(Val * 37ULL);
@@ -224,12 +226,12 @@ struct DenseMapInfo<std::pair<T, U>> {
224226
using FirstInfo = DenseMapInfo<T>;
225227
using SecondInfo = DenseMapInfo<U>;
226228

227-
static inline Pair getEmptyKey() {
229+
static constexpr Pair getEmptyKey() {
228230
return std::make_pair(FirstInfo::getEmptyKey(),
229231
SecondInfo::getEmptyKey());
230232
}
231233

232-
static inline Pair getTombstoneKey() {
234+
static constexpr Pair getTombstoneKey() {
233235
return std::make_pair(FirstInfo::getTombstoneKey(),
234236
SecondInfo::getTombstoneKey());
235237
}
@@ -257,11 +259,11 @@ struct DenseMapInfo<std::pair<T, U>> {
257259
template <typename... Ts> struct DenseMapInfo<std::tuple<Ts...>> {
258260
using Tuple = std::tuple<Ts...>;
259261

260-
static inline Tuple getEmptyKey() {
262+
static constexpr Tuple getEmptyKey() {
261263
return Tuple(DenseMapInfo<Ts>::getEmptyKey()...);
262264
}
263265

264-
static inline Tuple getTombstoneKey() {
266+
static constexpr Tuple getTombstoneKey() {
265267
return Tuple(DenseMapInfo<Ts>::getTombstoneKey()...);
266268
}
267269

@@ -309,10 +311,22 @@ struct DenseMapInfo<Enum, std::enable_if_t<std::is_enum_v<Enum>>> {
309311
using UnderlyingType = std::underlying_type_t<Enum>;
310312
using Info = DenseMapInfo<UnderlyingType>;
311313

312-
static Enum getEmptyKey() { return static_cast<Enum>(Info::getEmptyKey()); }
314+
// If an enum does not have a "fixed" underlying type, it may be UB to cast
315+
// some values of the underlying type to the enum. We use an "extra" constexpr
316+
// local to ensure that such UB would trigger "static assertion expression is
317+
// not an integral constant expression", rather than runtime UB.
318+
//
319+
// If you hit this error, you can fix by switching to `enum class`, or adding
320+
// an explicit underlying type (e.g. `enum X : int`) to the enum's definition.
321+
322+
static constexpr Enum getEmptyKey() {
323+
constexpr Enum V = static_cast<Enum>(Info::getEmptyKey());
324+
return V;
325+
}
313326

314-
static Enum getTombstoneKey() {
315-
return static_cast<Enum>(Info::getTombstoneKey());
327+
static constexpr Enum getTombstoneKey() {
328+
constexpr Enum V = static_cast<Enum>(Info::getTombstoneKey());
329+
return V;
316330
}
317331

318332
static unsigned getHashValue(const Enum &Val) {
@@ -326,9 +340,11 @@ template <typename T> struct DenseMapInfo<std::optional<T>> {
326340
using Optional = std::optional<T>;
327341
using Info = DenseMapInfo<T>;
328342

329-
static inline Optional getEmptyKey() { return {Info::getEmptyKey()}; }
343+
static constexpr Optional getEmptyKey() { return {Info::getEmptyKey()}; }
330344

331-
static inline Optional getTombstoneKey() { return {Info::getTombstoneKey()}; }
345+
static constexpr Optional getTombstoneKey() {
346+
return {Info::getTombstoneKey()};
347+
}
332348

333349
static unsigned getHashValue(const Optional &OptionalVal) {
334350
return detail::combineHashValue(

0 commit comments

Comments
 (0)