xref: /llvm-project/clang/unittests/StaticAnalyzer/RangeSetTest.cpp (revision 918972bded27de6a2bfacc15b4ad3edebd81f405)
1 //===- unittests/StaticAnalyzer/RangeSetTest.cpp ----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/Basic/Builtins.h"
10 #include "clang/Basic/FileManager.h"
11 #include "clang/Basic/SourceManager.h"
12 #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
13 #include "clang/Tooling/Tooling.h"
14 #include "llvm/ADT/APSInt.h"
15 #include "llvm/Support/raw_ostream.h"
16 #include "gtest/gtest.h"
17 
18 using namespace clang;
19 using namespace ento;
20 
21 namespace clang {
22 namespace ento {
23 
24 template <class RangeOrSet> static std::string toString(const RangeOrSet &Obj) {
25   std::string ObjRepresentation;
26   llvm::raw_string_ostream SS(ObjRepresentation);
27   Obj.dump(SS);
28   return ObjRepresentation;
29 }
30 LLVM_ATTRIBUTE_UNUSED static std::string toString(const llvm::APSInt &Point) {
31   return toString(Point, 10);
32 }
33 // We need it here for better fail diagnostics from gtest.
34 LLVM_ATTRIBUTE_UNUSED static std::ostream &operator<<(std::ostream &OS,
35                                                       const RangeSet &Set) {
36   return OS << toString(Set);
37 }
38 // We need it here for better fail diagnostics from gtest.
39 LLVM_ATTRIBUTE_UNUSED static std::ostream &operator<<(std::ostream &OS,
40                                                       const Range &R) {
41   return OS << toString(R);
42 }
43 LLVM_ATTRIBUTE_UNUSED static std::ostream &operator<<(std::ostream &OS,
44                                                       APSIntType Ty) {
45   return OS << (Ty.isUnsigned() ? "u" : "s") << Ty.getBitWidth();
46 }
47 
48 } // namespace ento
49 } // namespace clang
50 
51 namespace {
52 
53 template <class T> constexpr bool is_signed_v = std::is_signed<T>::value;
54 
55 template <typename T> struct TestValues {
56   static constexpr T MIN = std::numeric_limits<T>::min();
57   static constexpr T MAX = std::numeric_limits<T>::max();
58   // MID is a value in the middle of the range
59   // which unary minus does not affect on,
60   // e.g. int8/int32(0), uint8(128), uint32(2147483648).
61   static constexpr T MID =
62       is_signed_v<T> ? 0 : ~(static_cast<T>(-1) / static_cast<T>(2));
63   static constexpr T A = MID - (MAX - MID) / 3 * 2;
64   static constexpr T B = MID - (MAX - MID) / 3;
65   static constexpr T C = -B;
66   static constexpr T D = -A;
67 
68   static_assert(MIN < A && A < B && B < MID && MID < C && C < D && D < MAX,
69                 "Values shall be in an ascending order");
70   // Clear bits in low bytes by the given amount.
71   template <T Value, size_t Bytes>
72   static constexpr T ClearLowBytes =
73       static_cast<T>(static_cast<uint64_t>(Value)
74                      << ((Bytes >= CHAR_BIT) ? 0 : Bytes) * CHAR_BIT);
75 
76   template <T Value, typename Base>
77   static constexpr T TruncZeroOf = ClearLowBytes<Value + 1, sizeof(Base)>;
78 
79   // Random number with active bits in every byte. 0xAAAA'AAAA
80   static constexpr T XAAA = static_cast<T>(
81       0b10101010'10101010'10101010'10101010'10101010'10101010'10101010'10101010);
82   template <typename Base>
83   static constexpr T XAAATruncZeroOf = TruncZeroOf<XAAA, Base>; // 0xAAAA'AB00
84 
85   // Random number with active bits in every byte. 0x5555'5555
86   static constexpr T X555 = static_cast<T>(
87       0b01010101'01010101'01010101'01010101'01010101'01010101'01010101'01010101);
88   template <typename Base>
89   static constexpr T X555TruncZeroOf = TruncZeroOf<X555, Base>; // 0x5555'5600
90 
91 // Silence 'warning C4309: 'initializing': truncation of constant value'
92 //   in RangeSetCastToPromotionConversionTest.
93 #if defined(_MSC_VER) && !defined(__clang__)
94 #pragma warning(push)
95 #pragma warning(disable : 4309)
96 #endif
97   // Numbers for ranges with the same bits in the lowest byte.
98   // 0xAAAA'AA2A
99   static constexpr T FromA = ClearLowBytes<XAAA, sizeof(T) - 1> + 42;
100   static constexpr T ToA = FromA + 2; // 0xAAAA'AA2C
101   // 0x5555'552A
102   static constexpr T FromB = ClearLowBytes<X555, sizeof(T) - 1> + 42;
103   static constexpr T ToB = FromB + 2; // 0x5555'552C
104 
105 #if defined(_MSC_VER) && !defined(__clang__)
106 #pragma warning(pop)
107 #endif
108 };
109 
110 template <typename T>
111 static constexpr APSIntType APSIntTy =
112     APSIntType(sizeof(T) * CHAR_BIT, !is_signed_v<T>);
113 
114 template <typename BaseType> class RangeSetTest : public testing::Test {
115 public:
116   // Init block
117   std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCode("struct foo;");
118   ASTContext &Context = AST->getASTContext();
119   llvm::BumpPtrAllocator Arena;
120   BasicValueFactory BVF{Context, Arena};
121   RangeSet::Factory F{BVF};
122   // End init block
123 
124   using Self = RangeSetTest<BaseType>;
125   template <typename T> using RawRangeT = std::pair<T, T>;
126   template <typename T>
127   using RawRangeSetT = std::initializer_list<RawRangeT<T>>;
128   using RawRange = RawRangeT<BaseType>;
129   using RawRangeSet = RawRangeSetT<BaseType>;
130 
131   template <typename T> const llvm::APSInt &from(T X) {
132     static llvm::APSInt Int = APSIntTy<T>.getZeroValue();
133     Int = X;
134     return BVF.getValue(Int);
135   }
136 
137   template <typename T> Range from(const RawRangeT<T> &Init) {
138     return Range(from(Init.first), from(Init.second));
139   }
140 
141   template <typename T>
142   RangeSet from(RawRangeSetT<T> Init, APSIntType Ty = APSIntTy<BaseType>) {
143     RangeSet RangeSet = F.getEmptySet();
144     for (const auto &Raw : Init) {
145       RangeSet = F.add(RangeSet, from(Raw));
146     }
147     return RangeSet;
148   }
149 
150   template <class F, class... RawArgTypes>
151   void wrap(F ActualFunction, RawArgTypes &&... Args) {
152     (this->*ActualFunction)(from(std::forward<RawArgTypes>(Args))...);
153   }
154 
155   void checkNegateImpl(RangeSet Original, RangeSet Expected) {
156     RangeSet NegatedFromOriginal = F.negate(Original);
157     EXPECT_EQ(NegatedFromOriginal, Expected);
158     // Negate negated back and check with original.
159     RangeSet NegatedBackward = F.negate(NegatedFromOriginal);
160     EXPECT_EQ(NegatedBackward, Original);
161   }
162 
163   void checkNegate(RawRangeSet RawOriginal, RawRangeSet RawExpected) {
164     wrap(&Self::checkNegateImpl, RawOriginal, RawExpected);
165   }
166 
167   template <class PointOrSet>
168   void checkIntersectImpl(RangeSet LHS, PointOrSet RHS, RangeSet Expected) {
169     RangeSet Result = F.intersect(LHS, RHS);
170     EXPECT_EQ(Result, Expected)
171         << "while intersecting " << toString(LHS) << " and " << toString(RHS);
172   }
173 
174   void checkIntersectRangeImpl(RangeSet LHS, const llvm::APSInt &Lower,
175                                const llvm::APSInt &Upper, RangeSet Expected) {
176     RangeSet Result = F.intersect(LHS, Lower, Upper);
177     EXPECT_EQ(Result, Expected)
178         << "while intersecting " << toString(LHS) << " and [" << toString(Lower)
179         << ", " << toString(Upper) << "]";
180   }
181 
182   void checkIntersect(RawRangeSet RawLHS, RawRangeSet RawRHS,
183                       RawRangeSet RawExpected) {
184     wrap(&Self::checkIntersectImpl<RangeSet>, RawLHS, RawRHS, RawExpected);
185   }
186 
187   void checkIntersect(RawRangeSet RawLHS, BaseType RawRHS,
188                       RawRangeSet RawExpected) {
189     wrap(&Self::checkIntersectImpl<const llvm::APSInt &>, RawLHS, RawRHS,
190          RawExpected);
191   }
192 
193   void checkIntersect(RawRangeSet RawLHS, BaseType RawLower, BaseType RawUpper,
194                       RawRangeSet RawExpected) {
195     wrap(&Self::checkIntersectRangeImpl, RawLHS, RawLower, RawUpper,
196          RawExpected);
197   }
198 
199   void checkContainsImpl(RangeSet LHS, const llvm::APSInt &RHS, bool Expected) {
200     bool Result = LHS.contains(RHS);
201     EXPECT_EQ(Result, Expected)
202         << toString(LHS) << (Result ? " contains " : " doesn't contain ")
203         << toString(RHS);
204   }
205 
206   void checkContains(RawRangeSet RawLHS, BaseType RawRHS, bool Expected) {
207     checkContainsImpl(from(RawLHS), from(RawRHS), Expected);
208   }
209 
210   template <class RHSType>
211   void checkAddImpl(RangeSet LHS, RHSType RHS, RangeSet Expected) {
212     RangeSet Result = F.add(LHS, RHS);
213     EXPECT_EQ(Result, Expected)
214         << "while adding " << toString(LHS) << " and " << toString(RHS);
215   }
216 
217   void checkAdd(RawRangeSet RawLHS, RawRange RawRHS, RawRangeSet RawExpected) {
218     wrap(&Self::checkAddImpl<Range>, RawLHS, RawRHS, RawExpected);
219   }
220 
221   void checkAdd(RawRangeSet RawLHS, RawRangeSet RawRHS,
222                 RawRangeSet RawExpected) {
223     wrap(&Self::checkAddImpl<RangeSet>, RawLHS, RawRHS, RawExpected);
224   }
225 
226   void checkAdd(RawRangeSet RawLHS, BaseType RawRHS, RawRangeSet RawExpected) {
227     wrap(&Self::checkAddImpl<const llvm::APSInt &>, RawLHS, RawRHS,
228          RawExpected);
229   }
230 
231   template <class RHSType>
232   void checkUniteImpl(RangeSet LHS, RHSType RHS, RangeSet Expected) {
233     RangeSet Result = F.unite(LHS, RHS);
234     EXPECT_EQ(Result, Expected)
235         << "while uniting " << toString(LHS) << " and " << toString(RHS);
236   }
237 
238   void checkUnite(RawRangeSet RawLHS, RawRange RawRHS,
239                   RawRangeSet RawExpected) {
240     wrap(&Self::checkUniteImpl<Range>, RawLHS, RawRHS, RawExpected);
241   }
242 
243   void checkUnite(RawRangeSet RawLHS, RawRangeSet RawRHS,
244                   RawRangeSet RawExpected) {
245     wrap(&Self::checkUniteImpl<RangeSet>, RawLHS, RawRHS, RawExpected);
246   }
247 
248   void checkUnite(RawRangeSet RawLHS, BaseType RawRHS,
249                   RawRangeSet RawExpected) {
250     wrap(&Self::checkUniteImpl<const llvm::APSInt &>, RawLHS, RawRHS,
251          RawExpected);
252   }
253 
254   void checkDeleteImpl(const llvm::APSInt &Point, RangeSet From,
255                        RangeSet Expected) {
256     RangeSet Result = F.deletePoint(From, Point);
257     EXPECT_EQ(Result, Expected)
258         << "while deleting " << toString(Point) << " from " << toString(From);
259   }
260 
261   void checkDelete(BaseType Point, RawRangeSet RawFrom,
262                    RawRangeSet RawExpected) {
263     wrap(&Self::checkDeleteImpl, Point, RawFrom, RawExpected);
264   }
265 
266   void checkCastToImpl(RangeSet What, APSIntType Ty, RangeSet Expected) {
267     RangeSet Result = F.castTo(What, Ty);
268     EXPECT_EQ(Result, Expected)
269         << "while casting " << toString(What) << " to " << Ty;
270   }
271 
272   template <typename From, typename To>
273   void checkCastTo(RawRangeSetT<From> What, RawRangeSetT<To> Expected) {
274     static constexpr APSIntType FromTy = APSIntTy<From>;
275     static constexpr APSIntType ToTy = APSIntTy<To>;
276     this->checkCastToImpl(from(What, FromTy), ToTy, from(Expected, ToTy));
277   }
278 };
279 
280 using IntTypes = ::testing::Types<int8_t, uint8_t, int16_t, uint16_t, int32_t,
281                                   uint32_t, int64_t, uint64_t>;
282 TYPED_TEST_SUITE(RangeSetTest, IntTypes, );
283 
284 TYPED_TEST(RangeSetTest, RangeSetNegateTest) {
285   using TV = TestValues<TypeParam>;
286   constexpr auto MIN = TV::MIN;
287   constexpr auto MAX = TV::MAX;
288   constexpr auto MID = TV::MID;
289   constexpr auto A = TV::A;
290   constexpr auto B = TV::B;
291   constexpr auto C = TV::C;
292   constexpr auto D = TV::D;
293 
294   this->checkNegate({{MIN, A}}, {{MIN, MIN}, {D, MAX}});
295   this->checkNegate({{MIN, C}}, {{MIN, MIN}, {B, MAX}});
296   this->checkNegate({{MIN, MID}}, {{MIN, MIN}, {MID, MAX}});
297   this->checkNegate({{MIN, MAX}}, {{MIN, MAX}});
298   this->checkNegate({{A, D}}, {{A, D}});
299   this->checkNegate({{A, B}}, {{C, D}});
300   this->checkNegate({{MIN, A}, {D, MAX}}, {{MIN, A}, {D, MAX}});
301   this->checkNegate({{MIN, B}, {MID, D}}, {{MIN, MIN}, {A, MID}, {C, MAX}});
302   this->checkNegate({{MIN, MID}, {C, D}}, {{MIN, MIN}, {A, B}, {MID, MAX}});
303   this->checkNegate({{MIN, MID}, {C, MAX}}, {{MIN, B}, {MID, MAX}});
304   this->checkNegate({{A, MID}, {D, MAX}}, {{MIN + 1, A}, {MID, D}});
305   this->checkNegate({{A, A}}, {{D, D}});
306   this->checkNegate({{MID, MID}}, {{MID, MID}});
307   this->checkNegate({{MAX, MAX}}, {{MIN + 1, MIN + 1}});
308 }
309 
310 TYPED_TEST(RangeSetTest, RangeSetPointIntersectTest) {
311   // Check that we can correctly intersect empty sets.
312   this->checkIntersect({}, 42, {});
313   // Check that intersection with itself produces the same set.
314   this->checkIntersect({{42, 42}}, 42, {{42, 42}});
315   // Check more general cases.
316   this->checkIntersect({{0, 10}, {20, 30}, {30, 40}, {50, 60}}, 42, {});
317   this->checkIntersect({{0, 10}, {20, 30}, {30, 60}}, 42, {{42, 42}});
318 }
319 
320 TYPED_TEST(RangeSetTest, RangeSetRangeIntersectTest) {
321   using TV = TestValues<TypeParam>;
322   constexpr auto MIN = TV::MIN;
323   constexpr auto MAX = TV::MAX;
324 
325   // Check that we can correctly intersect empty sets.
326   this->checkIntersect({}, 10, 20, {});
327   this->checkIntersect({}, 20, 10, {});
328   // Check that intersection with itself produces the same set.
329   this->checkIntersect({{10, 20}}, 10, 20, {{10, 20}});
330   this->checkIntersect({{MIN, 10}, {20, MAX}}, 20, 10, {{MIN, 10}, {20, MAX}});
331   // Check non-overlapping range intersections.
332   this->checkIntersect({{10, 20}}, 21, 9, {});
333   this->checkIntersect({{MIN, 9}, {21, MAX}}, 10, 20, {});
334   // Check more general cases.
335   this->checkIntersect({{0, 10}, {20, 30}, {30, 40}, {50, 60}}, 10, 35,
336                        {{10, 10}, {20, 30}, {30, 35}});
337   this->checkIntersect({{0, 10}, {20, 30}, {30, 40}, {50, 60}}, 35, 10,
338                        {{0, 10}, {35, 40}, {50, 60}});
339 }
340 
341 TYPED_TEST(RangeSetTest, RangeSetGenericIntersectTest) {
342   // Check that we can correctly intersect empty sets.
343   this->checkIntersect({}, {}, {});
344   this->checkIntersect({}, {{0, 10}}, {});
345   this->checkIntersect({{0, 10}}, {}, {});
346 
347   this->checkIntersect({{0, 10}}, {{4, 6}}, {{4, 6}});
348   this->checkIntersect({{0, 10}}, {{4, 20}}, {{4, 10}});
349   // Check that intersection with points works as expected.
350   this->checkIntersect({{0, 10}}, {{4, 4}}, {{4, 4}});
351   // All ranges are closed, check that intersection with edge points works as
352   // expected.
353   this->checkIntersect({{0, 10}}, {{10, 10}}, {{10, 10}});
354 
355   // Let's check that we can skip some intervals and partially intersect
356   // other intervals.
357   this->checkIntersect({{0, 2}, {4, 5}, {6, 9}, {10, 11}, {12, 12}, {13, 15}},
358                        {{8, 14}, {20, 30}},
359                        {{8, 9}, {10, 11}, {12, 12}, {13, 14}});
360   // Check more generic case.
361   this->checkIntersect(
362       {{0, 1}, {2, 3}, {5, 6}, {7, 15}, {25, 30}},
363       {{4, 10}, {11, 11}, {12, 16}, {17, 17}, {19, 20}, {21, 23}, {24, 27}},
364       {{5, 6}, {7, 10}, {11, 11}, {12, 15}, {25, 27}});
365 }
366 
367 TYPED_TEST(RangeSetTest, RangeSetContainsTest) {
368   // Check with an empty set.
369   this->checkContains({}, 10, false);
370   // Check contains with sets of size one:
371   //   * when the whole range is less
372   this->checkContains({{0, 5}}, 10, false);
373   //   * when the whole range is greater
374   this->checkContains({{20, 25}}, 10, false);
375   //   * when the range is just the point we are looking for
376   this->checkContains({{10, 10}}, 10, true);
377   //   * when the range starts with the point
378   this->checkContains({{10, 15}}, 10, true);
379   //   * when the range ends with the point
380   this->checkContains({{5, 10}}, 10, true);
381   //   * when the range has the point somewhere in the middle
382   this->checkContains({{0, 25}}, 10, true);
383   // Check similar cases, but with larger sets.
384   this->checkContains({{0, 5}, {10, 10}, {15, 20}}, 10, true);
385   this->checkContains({{0, 5}, {10, 12}, {15, 20}}, 10, true);
386   this->checkContains({{0, 5}, {5, 7}, {8, 10}, {12, 41}}, 10, true);
387 
388   using TV = TestValues<TypeParam>;
389   constexpr auto MIN = TV::MIN;
390   constexpr auto MAX = TV::MAX;
391   constexpr auto MID = TV::MID;
392 
393   this->checkContains({{MIN, MAX}}, 0, true);
394   this->checkContains({{MIN, MAX}}, MID, true);
395   this->checkContains({{MIN, MAX}}, -10, true);
396   this->checkContains({{MIN, MAX}}, 10, true);
397 }
398 
399 TYPED_TEST(RangeSetTest, RangeSetAddTest) {
400   // Check adding single points
401   this->checkAdd({}, 10, {{10, 10}});
402   this->checkAdd({{0, 5}}, 10, {{0, 5}, {10, 10}});
403   this->checkAdd({{0, 5}, {30, 40}}, 10, {{0, 5}, {10, 10}, {30, 40}});
404 
405   // Check adding single ranges.
406   this->checkAdd({}, {10, 20}, {{10, 20}});
407   this->checkAdd({{0, 5}}, {10, 20}, {{0, 5}, {10, 20}});
408   this->checkAdd({{0, 5}, {30, 40}}, {10, 20}, {{0, 5}, {10, 20}, {30, 40}});
409 
410   // Check adding whole sets of ranges.
411   this->checkAdd({{0, 5}}, {{10, 20}}, {{0, 5}, {10, 20}});
412   // Check that ordering of ranges is as expected.
413   this->checkAdd({{0, 5}, {30, 40}}, {{10, 20}}, {{0, 5}, {10, 20}, {30, 40}});
414   this->checkAdd({{0, 5}, {30, 40}}, {{10, 20}, {50, 60}},
415                  {{0, 5}, {10, 20}, {30, 40}, {50, 60}});
416   this->checkAdd({{10, 20}, {50, 60}}, {{0, 5}, {30, 40}, {70, 80}},
417                  {{0, 5}, {10, 20}, {30, 40}, {50, 60}, {70, 80}});
418 }
419 
420 TYPED_TEST(RangeSetTest, RangeSetDeletePointTest) {
421   using TV = TestValues<TypeParam>;
422   constexpr auto MIN = TV::MIN;
423   constexpr auto MAX = TV::MAX;
424   constexpr auto MID = TV::MID;
425 
426   this->checkDelete(MID, {{MIN, MAX}}, {{MIN, MID - 1}, {MID + 1, MAX}});
427   // Check that delete works with an empty set.
428   this->checkDelete(10, {}, {});
429   // Check that delete can remove entire ranges.
430   this->checkDelete(10, {{10, 10}}, {});
431   this->checkDelete(10, {{0, 5}, {10, 10}, {20, 30}}, {{0, 5}, {20, 30}});
432   // Check that delete can split existing ranges into two.
433   this->checkDelete(10, {{0, 5}, {7, 15}, {20, 30}},
434                     {{0, 5}, {7, 9}, {11, 15}, {20, 30}});
435   // Check that delete of the point not from the range set works as expected.
436   this->checkDelete(10, {{0, 5}, {20, 30}}, {{0, 5}, {20, 30}});
437 }
438 
439 TYPED_TEST(RangeSetTest, RangeSetUniteTest) {
440   using TV = TestValues<TypeParam>;
441   constexpr auto MIN = TV::MIN;
442   constexpr auto MAX = TV::MAX;
443   constexpr auto MID = TV::MID;
444   constexpr auto A = TV::A;
445   constexpr auto B = TV::B;
446   constexpr auto C = TV::C;
447   constexpr auto D = TV::D;
448 
449   // LHS and RHS is empty.
450   // RHS =>
451   // LHS =>                     =
452   //        ___________________   ___________________
453   this->checkUnite({}, {}, {});
454 
455   // RHS is empty.
456   // RHS =>
457   // LHS =>        _____        =        _____
458   //        ______/_____\______   ______/_____\______
459   this->checkUnite({{A, B}}, {}, {{A, B}});
460   this->checkUnite({{A, B}, {C, D}}, {}, {{A, B}, {C, D}});
461   this->checkUnite({{MIN, MIN}}, {}, {{MIN, MIN}});
462   this->checkUnite({{MAX, MAX}}, {}, {{MAX, MAX}});
463   this->checkUnite({{MIN, MIN}, {MAX, MAX}}, {}, {{MIN, MIN}, {MAX, MAX}});
464 
465   // LHS is empty.
466   // RHS =>         ___
467   // LHS =>        /   \        =        _____
468   //        ______/_____\______   ______/_____\______
469   this->checkUnite({}, B, {{B, B}});
470   this->checkUnite({}, {B, C}, {{B, C}});
471   this->checkUnite({}, {{MIN, B}, {C, MAX}}, {{MIN, B}, {C, MAX}});
472   this->checkUnite({}, {{MIN, MIN}}, {{MIN, MIN}});
473   this->checkUnite({}, {{MAX, MAX}}, {{MAX, MAX}});
474   this->checkUnite({}, {{MIN, MIN}, {MAX, MAX}}, {{MIN, MIN}, {MAX, MAX}});
475 
476   // RHS is detached from LHS.
477   // RHS =>             ___
478   // LHS =>    ___     /   \    =    ___     _____
479   //        __/___\___/_____\__   __/___\___/_____\__
480   this->checkUnite({{A, C}}, D, {{A, C}, {D, D}});
481   this->checkUnite({{MID, C}, {D, MAX}}, A, {{A, A}, {MID, C}, {D, MAX}});
482   this->checkUnite({{A, B}}, {MID, D}, {{A, B}, {MID, D}});
483   this->checkUnite({{MIN, A}, {D, MAX}}, {B, C}, {{MIN, A}, {B, C}, {D, MAX}});
484   this->checkUnite({{B, MID}, {D, MAX}}, {{MIN, A}, {C, C}},
485                    {{MIN, A}, {B, MID}, {C, C}, {D, MAX}});
486   this->checkUnite({{MIN, A}, {C, C}}, {{B, MID}, {D, MAX}},
487                    {{MIN, A}, {B, MID}, {C, C}, {D, MAX}});
488   this->checkUnite({{A, B}}, {{MAX, MAX}}, {{A, B}, {MAX, MAX}});
489   this->checkUnite({{MIN, MIN}}, {A, B}, {{MIN, MIN}, {A, B}});
490   this->checkUnite({{MIN, MIN}}, {MAX, MAX}, {{MIN, MIN}, {MAX, MAX}});
491 
492   // RHS is inside LHS.
493   // RHS =>         ___
494   // LHS =>     ___/___\___     =     ___________
495   //        ___/__/_____\__\___   ___/___________\___
496   this->checkUnite({{A, C}}, MID, {{A, C}});
497   this->checkUnite({{A, D}}, {B, C}, {{A, D}});
498   this->checkUnite({{MIN, MAX}}, {B, C}, {{MIN, MAX}});
499 
500   // RHS wraps LHS.
501   // RHS =>      _________
502   // LHS =>     /  _____  \     =     ___________
503   //        ___/__/_____\__\___   ___/___________\___
504   this->checkUnite({{MID, MID}}, {A, D}, {{A, D}});
505   this->checkUnite({{B, C}}, {A, D}, {{A, D}});
506   this->checkUnite({{A, B}}, {MIN, MAX}, {{MIN, MAX}});
507 
508   // RHS equals to LHS.
509   // RHS =>      _________
510   // LHS =>     /_________\     =     ___________
511   //        ___/___________\___   ___/___________\___
512   this->checkUnite({{MIN, MIN}}, MIN, {{MIN, MIN}});
513   this->checkUnite({{A, B}}, {A, B}, {{A, B}});
514   this->checkUnite({{MAX, MAX}}, {{MAX, MAX}}, {{MAX, MAX}});
515   this->checkUnite({{MIN, MIN}}, {{MIN, MIN}}, {{MIN, MIN}});
516   this->checkUnite({{MIN, MIN}, {MAX, MAX}}, {{MIN, MIN}, {MAX, MAX}},
517                    {{MIN, MIN}, {MAX, MAX}});
518 
519   // RHS edge is MIN and attached and inside LHS.
520   // RHS =>   _____
521   // LHS =>  /_____\_____     =  ___________
522   //        /_______\____\___   /___________\___
523   this->checkUnite({{MIN, A}}, {MIN, B}, {{MIN, B}});
524 
525   // RHS edge is MIN and attached and outsude LHS.
526   // RHS =>   __________
527   // LHS =>  /______    \     =  ___________
528   //        /_______\____\___   /___________\___
529   this->checkUnite({{MIN, B}}, {MIN, A}, {{MIN, B}});
530 
531   // RHS intersects right of LHS.
532   // RHS =>         ______
533   // LHS =>     ___/____  \     =     ___________
534   //        ___/__/_____\__\___   ___/___________\___
535   this->checkUnite({{A, C}}, C, {{A, C}});
536   this->checkUnite({{A, C}}, {B, D}, {{A, D}});
537 
538   // RHS intersects left of LHS.
539   // RHS =>      ______
540   // LHS =>     /  ____\___     =     ___________
541   //        ___/__/_____\__\___   ___/___________\___
542   this->checkUnite({{B, D}}, B, {{B, D}});
543   this->checkUnite({{B, D}}, {A, C}, {{A, D}});
544   this->checkUnite({{MID, MAX}}, {MIN, MID}, {{MIN, MAX}});
545 
546   // RHS adjacent to LHS on right.
547   // RHS =>            _____
548   // LHS =>   ______  /     \   =   _______________
549   //        _/______\/_______\_   _/_______________\_
550   this->checkUnite({{A, B - 1}}, B, {{A, B}});
551   this->checkUnite({{A, C}}, {C + 1, D}, {{A, D}});
552   this->checkUnite({{MIN, MID}}, {MID + 1, MAX}, {{MIN, MAX}});
553 
554   // RHS adjacent to LHS on left.
555   // RHS =>    _____
556   // LHS =>   /     \  ______   =   _______________
557   //        _/_______\/______\_   _/_______________\_
558   this->checkUnite({{B + 1, C}}, B, {{B, C}});
559   this->checkUnite({{B, D}}, {A, B - 1}, {{A, D}});
560 
561   // RHS adjacent to LHS in between.
562   // RHS =>         ___
563   // LHS =>   ___  /   \  ___   =   _______________
564   //        _/___\/_____\/___\_   _/_______________\_
565   this->checkUnite({{A, MID - 1}, {MID + 1, D}}, MID, {{A, D}});
566   this->checkUnite({{MIN, A}, {D, MAX}}, {A + 1, D - 1}, {{MIN, MAX}});
567 
568   // RHS adjacent to LHS on the outside.
569   // RHS =>    __         __
570   // LHS =>   /  \  ___  /  \   =   _______________
571   //        _/____\/___\/____\_   _/_______________\_
572   this->checkUnite({{C, C}}, {{A, C - 1}, {C + 1, D}}, {{A, D}});
573   this->checkUnite({{B, MID}}, {{A, B - 1}, {MID + 1, D}}, {{A, D}});
574 
575   // RHS wraps two subranges of LHS.
576   // RHS =>     ___________
577   // LHS =>    / ___   ___ \    =    _____________
578   //        __/_/___\_/___\_\__   __/_____________\__
579   this->checkUnite({{B, B}, {MID, MID}, {C, C}}, {{A, D}}, {{A, D}});
580   this->checkUnite({{A, B}, {MID, C}}, {{MIN, D}}, {{MIN, D}});
581 
582   // RHS intersects two subranges of LHS.
583   // RHS =>      _________
584   // LHS =>   __/__      _\__   =   _______________
585   //        _/_/___\____/__\_\_   _/_______________\_
586   this->checkUnite({{MIN, B}, {C, MAX}}, {{A, D}}, {{MIN, MAX}});
587   this->checkUnite({{A, MID}, {C, MAX}}, {{B, D}}, {{A, MAX}});
588 
589   // Multiple intersections.
590 
591   // clang-format off
592   // RHS =>
593   // LHS =>   /\   /\            =   __   __
594   //        _/__\_/__\_/\_/\_/\_   _/__\_/__\_/\_/\_/\_
595   this->checkUnite({{MID, C}, {C + 2, D - 2}, {D, MAX}},
596                    {{MIN, A}, {A + 2, B}},
597                    {{MIN, A}, {A + 2, B}, {MID, C}, {C + 2, D - 2}, {D, MAX}});
598   this->checkUnite({{B, B}, {C, C}, {MAX, MAX}},
599                    {{MIN, MIN}, {A, A}},
600                    {{MIN, MIN}, {A, A}, {B, B}, {C, C}, {MAX, MAX}});
601 
602   // RHS =>
603   // LHS =>             /\   /\   =            __   __
604   //        _/\_/\_/\__/__\_/__\_   _/\_/\_/\_/__\_/__\_
605   this->checkUnite({{MIN, A}, {A + 2, B}, {MID, C}},
606                    {{C + 2, D - 2}, {D, MAX}},
607                    {{MIN, A}, {A + 2, B}, {MID, C}, {C + 2, D - 2}, {D, MAX}});
608   this->checkUnite({{MIN, MIN}, {A, A}, {B, B}},
609                    {{C, C}, {MAX, MAX}},
610                    {{MIN, MIN}, {A, A}, {B, B}, {C, C}, {MAX, MAX}});
611 
612   // RHS =>
613   // LHS =>   _   /\   _   /\   _   /\  =
614   //        _/_\_/__\_/_\_/__\_/_\_/__\_
615   //
616   // RSLT =>  _   __   _   __   _   __
617   //        _/_\_/__\_/_\_/__\_/_\_/__\_
618   this->checkUnite({{MIN, A}, {B + 2, MID}, {C + 2, D}},
619                    {{A + 2, B}, {MID + 2, C}, {D + 2, MAX}},
620                    {{MIN, A}, {A + 2, B}, {B + 2, MID}, {MID + 2, C}, {C + 2, D}, {D + 2, MAX}});
621   this->checkUnite({{MIN, MIN}, {B, B}, {D, D}},
622                    {{A, A}, {C, C}, {MAX, MAX}},
623                    {{MIN, MIN}, {A, A}, {B, B}, {C, C}, {D, D}, {MAX, MAX}});
624 
625   // RHS =>
626   // LHS =>   /\   _   /\   _   /\   _  =
627   //        _/__\_/_\_/__\_/_\_/__\_/_\_
628   //
629   // RSLT =>  __   _   __   _   __   _
630   //        _/__\_/_\_/__\_/_\_/__\_/_\_
631   this->checkUnite({{A + 2, B}, {MID + 2, C}, {D + 2, MAX}},
632                    {{MIN, A}, {B + 2, MID}, {C + 2, D}},
633                    {{MIN, A}, {A + 2, B}, {B + 2, MID}, {MID + 2, C}, {C + 2, D}, {D + 2, MAX}});
634   this->checkUnite({{A, A}, {C, C}, {MAX, MAX}},
635                    {{MIN, MIN}, {B, B}, {D, D}},
636                    {{MIN, MIN}, {A, A}, {B, B}, {C, C}, {D, D}, {MAX, MAX}});
637 
638   // RHS =>    _     __       _
639   // LHS =>   /_\   /_ \  _  / \   =   ___   ____________
640   //        _/___\_/__\_\/_\/___\_   _/___\_/____________\_
641   this->checkUnite({{MIN, A}, {B, C}, {D, MAX}},
642                    {{MIN, A}, {B, C - 2}, {C + 1, D - 1}},
643                    {{MIN, A}, {B, MAX}});
644   this->checkUnite({{A, A}, {B, MID}, {D, D}},
645                    {{A, A}, {B, B}, {MID + 1, D - 1}},
646                    {{A, A}, {B, D}});
647 
648   // RHS =>            ___      ___
649   // LHS =>      /\  _/_  \_   / _ \   /\  =
650   //        _/\_/__\//__\ /\\_/_/_\_\_/__\_
651   //
652   // RSLT =>     ___________   _____   __
653   //        _/\_/___________\_/_____\_/__\_
654   this->checkUnite({{MIN, MIN}, {B, MID}, {MID + 1, C}, {C + 4, D - 1}},
655                    {{A, B - 1}, {B + 1, C - 1}, {C + 2, D}, {MAX - 1, MAX}},
656                    {{MIN, MIN}, {A, C}, {C + 2, D}, {MAX - 1, MAX}});
657   // clang-format on
658 }
659 
660 template <typename From, typename To> struct CastType {
661   using FromType = From;
662   using ToType = To;
663 };
664 
665 template <typename Type>
666 class RangeSetCastToNoopTest : public RangeSetTest<typename Type::FromType> {};
667 template <typename Type>
668 class RangeSetCastToPromotionTest
669     : public RangeSetTest<typename Type::FromType> {};
670 template <typename Type>
671 class RangeSetCastToTruncationTest
672     : public RangeSetTest<typename Type::FromType> {};
673 template <typename Type>
674 class RangeSetCastToConversionTest
675     : public RangeSetTest<typename Type::FromType> {};
676 template <typename Type>
677 class RangeSetCastToPromotionConversionTest
678     : public RangeSetTest<typename Type::FromType> {};
679 template <typename Type>
680 class RangeSetCastToTruncationConversionTest
681     : public RangeSetTest<typename Type::FromType> {};
682 
683 using NoopCastTypes =
684     ::testing::Types<CastType<int8_t, int8_t>, CastType<uint8_t, uint8_t>,
685                      CastType<int16_t, int16_t>, CastType<uint16_t, uint16_t>,
686                      CastType<int32_t, int32_t>, CastType<uint32_t, uint32_t>,
687                      CastType<int64_t, int64_t>, CastType<uint64_t, uint64_t>>;
688 
689 using PromotionCastTypes =
690     ::testing::Types<CastType<int8_t, int16_t>, CastType<int8_t, int32_t>,
691                      CastType<int8_t, int64_t>, CastType<uint8_t, uint16_t>,
692                      CastType<uint8_t, uint32_t>, CastType<uint8_t, uint64_t>,
693                      CastType<int16_t, int32_t>, CastType<int16_t, int64_t>,
694                      CastType<uint16_t, uint32_t>, CastType<uint16_t, uint64_t>,
695                      CastType<int32_t, int64_t>, CastType<uint32_t, uint64_t>>;
696 
697 using TruncationCastTypes =
698     ::testing::Types<CastType<int16_t, int8_t>, CastType<uint16_t, uint8_t>,
699                      CastType<int32_t, int16_t>, CastType<int32_t, int8_t>,
700                      CastType<uint32_t, uint16_t>, CastType<uint32_t, uint8_t>,
701                      CastType<int64_t, int32_t>, CastType<int64_t, int16_t>,
702                      CastType<int64_t, int8_t>, CastType<uint64_t, uint32_t>,
703                      CastType<uint64_t, uint16_t>, CastType<uint64_t, uint8_t>>;
704 
705 using ConversionCastTypes =
706     ::testing::Types<CastType<int8_t, uint8_t>, CastType<uint8_t, int8_t>,
707                      CastType<int16_t, uint16_t>, CastType<uint16_t, int16_t>,
708                      CastType<int32_t, uint32_t>, CastType<uint32_t, int32_t>,
709                      CastType<int64_t, uint64_t>, CastType<uint64_t, int64_t>>;
710 
711 using PromotionConversionCastTypes =
712     ::testing::Types<CastType<int8_t, uint16_t>, CastType<int8_t, uint32_t>,
713                      CastType<int8_t, uint64_t>, CastType<uint8_t, int16_t>,
714                      CastType<uint8_t, int32_t>, CastType<uint8_t, int64_t>,
715                      CastType<int16_t, uint32_t>, CastType<int16_t, uint64_t>,
716                      CastType<uint16_t, int32_t>, CastType<uint16_t, int64_t>,
717                      CastType<int32_t, uint64_t>, CastType<uint32_t, int64_t>>;
718 
719 using TruncationConversionCastTypes =
720     ::testing::Types<CastType<int16_t, uint8_t>, CastType<uint16_t, int8_t>,
721                      CastType<int32_t, uint16_t>, CastType<int32_t, uint8_t>,
722                      CastType<uint32_t, int16_t>, CastType<uint32_t, int8_t>,
723                      CastType<int64_t, uint32_t>, CastType<int64_t, uint16_t>,
724                      CastType<int64_t, uint8_t>, CastType<uint64_t, int32_t>,
725                      CastType<uint64_t, int16_t>, CastType<uint64_t, int8_t>>;
726 
727 TYPED_TEST_SUITE(RangeSetCastToNoopTest, NoopCastTypes, );
728 TYPED_TEST_SUITE(RangeSetCastToPromotionTest, PromotionCastTypes, );
729 TYPED_TEST_SUITE(RangeSetCastToTruncationTest, TruncationCastTypes, );
730 TYPED_TEST_SUITE(RangeSetCastToConversionTest, ConversionCastTypes, );
731 TYPED_TEST_SUITE(RangeSetCastToPromotionConversionTest,
732                  PromotionConversionCastTypes, );
733 TYPED_TEST_SUITE(RangeSetCastToTruncationConversionTest,
734                  TruncationConversionCastTypes, );
735 
736 TYPED_TEST(RangeSetCastToNoopTest, RangeSetCastToNoopTest) {
737   // Just to reduce the verbosity.
738   using F = typename TypeParam::FromType; // From
739   using T = typename TypeParam::ToType;   // To
740 
741   using TV = TestValues<F>;
742   constexpr auto MIN = TV::MIN;
743   constexpr auto MAX = TV::MAX;
744   constexpr auto MID = TV::MID;
745   constexpr auto B = TV::B;
746   constexpr auto C = TV::C;
747   // One point
748   this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}});
749   this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}});
750   this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}});
751   this->template checkCastTo<F, T>({{B, B}}, {{B, B}});
752   this->template checkCastTo<F, T>({{C, C}}, {{C, C}});
753   // Two points
754   this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}},
755                                    {{MIN, MIN}, {MAX, MAX}});
756   this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}});
757   this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}},
758                                    {{MID, MID}, {MAX, MAX}});
759   this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}});
760   this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}});
761   this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}});
762   this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}});
763   // One range
764   this->template checkCastTo<F, T>({{MIN, MAX}}, {{MIN, MAX}});
765   this->template checkCastTo<F, T>({{MIN, MID}}, {{MIN, MID}});
766   this->template checkCastTo<F, T>({{MID, MAX}}, {{MID, MAX}});
767   this->template checkCastTo<F, T>({{B, MAX}}, {{B, MAX}});
768   this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}});
769   this->template checkCastTo<F, T>({{MIN, C}}, {{MIN, C}});
770   this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}});
771   this->template checkCastTo<F, T>({{B, C}}, {{B, C}});
772   // Two ranges
773   this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{MIN, B}, {C, MAX}});
774   this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, {{B, MID}, {C, MAX}});
775   this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{MIN, B}, {MID, C}});
776 }
777 
778 TYPED_TEST(RangeSetCastToPromotionTest, Test) {
779   // Just to reduce the verbosity.
780   using F = typename TypeParam::FromType; // From
781   using T = typename TypeParam::ToType;   // To
782 
783   using TV = TestValues<F>;
784   constexpr auto MIN = TV::MIN;
785   constexpr auto MAX = TV::MAX;
786   constexpr auto MID = TV::MID;
787   constexpr auto B = TV::B;
788   constexpr auto C = TV::C;
789   // One point
790   this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}});
791   this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}});
792   this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}});
793   this->template checkCastTo<F, T>({{B, B}}, {{B, B}});
794   this->template checkCastTo<F, T>({{C, C}}, {{C, C}});
795   // Two points
796   this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}},
797                                    {{MIN, MIN}, {MAX, MAX}});
798   this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}});
799   this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}},
800                                    {{MID, MID}, {MAX, MAX}});
801   this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}});
802   this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}});
803   this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}});
804   this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}});
805   // One range
806   this->template checkCastTo<F, T>({{MIN, MAX}}, {{MIN, MAX}});
807   this->template checkCastTo<F, T>({{MIN, MID}}, {{MIN, MID}});
808   this->template checkCastTo<F, T>({{MID, MAX}}, {{MID, MAX}});
809   this->template checkCastTo<F, T>({{B, MAX}}, {{B, MAX}});
810   this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}});
811   this->template checkCastTo<F, T>({{MIN, C}}, {{MIN, C}});
812   this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}});
813   this->template checkCastTo<F, T>({{B, C}}, {{B, C}});
814   // Two ranges
815   this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{MIN, B}, {C, MAX}});
816   this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, {{B, MID}, {C, MAX}});
817   this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{MIN, B}, {MID, C}});
818 }
819 
820 TYPED_TEST(RangeSetCastToTruncationTest, Test) {
821   // Just to reduce the verbosity.
822   using F = typename TypeParam::FromType; // From
823   using T = typename TypeParam::ToType;   // To
824 
825   using TV = TestValues<F>;
826   constexpr auto MIN = TV::MIN;
827   constexpr auto MAX = TV::MAX;
828   constexpr auto MID = TV::MID;
829   constexpr auto B = TV::B;
830   constexpr auto C = TV::C;
831   // One point
832   //
833   // NOTE: We can't use ToMIN, ToMAX, ... everywhere. That would be incorrect:
834   // int16(-32768, 32767) -> int8(-128, 127),
835   //       aka (MIN, MAX) -> (ToMIN, ToMAX) // OK.
836   // int16(-32768, -32768) -> int8(-128, -128),
837   //        aka (MIN, MIN) -> (ToMIN, ToMIN) // NOK.
838   // int16(-32768,-32768) -> int8(0, 0),
839   //       aka (MIN, MIN) -> ((int8)MIN, (int8)MIN) // OK.
840   this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}});
841   this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}});
842   this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}});
843   this->template checkCastTo<F, T>({{B, B}}, {{B, B}});
844   this->template checkCastTo<F, T>({{C, C}}, {{C, C}});
845   // Two points
846   // Use `if constexpr` here.
847   if (is_signed_v<F>) {
848     this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, {{MAX, MIN}});
849     this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}}, {{MAX, MID}});
850   } else {
851     this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}},
852                                      {{MIN, MIN}, {MAX, MAX}});
853     this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}},
854                                      {{MID, MID}, {MAX, MAX}});
855   }
856   this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}});
857   this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}});
858   this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}});
859   this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}});
860   this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}});
861   // One range
862   constexpr auto ToMIN = TestValues<T>::MIN;
863   constexpr auto ToMAX = TestValues<T>::MAX;
864   this->template checkCastTo<F, T>({{MIN, MAX}}, {{ToMIN, ToMAX}});
865   this->template checkCastTo<F, T>({{MIN, MID}}, {{ToMIN, ToMAX}});
866   this->template checkCastTo<F, T>({{MID, MAX}}, {{ToMIN, ToMAX}});
867   this->template checkCastTo<F, T>({{B, MAX}}, {{ToMIN, ToMAX}});
868   this->template checkCastTo<F, T>({{C, MAX}}, {{ToMIN, ToMAX}});
869   this->template checkCastTo<F, T>({{MIN, C}}, {{ToMIN, ToMAX}});
870   this->template checkCastTo<F, T>({{MIN, B}}, {{ToMIN, ToMAX}});
871   this->template checkCastTo<F, T>({{B, C}}, {{ToMIN, ToMAX}});
872   // Two ranges
873   this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{ToMIN, ToMAX}});
874   this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, {{ToMIN, ToMAX}});
875   this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{ToMIN, ToMAX}});
876   constexpr auto XAAA = TV::XAAA;
877   constexpr auto X555 = TV::X555;
878   constexpr auto ZA = TV::template XAAATruncZeroOf<T>;
879   constexpr auto Z5 = TV::template X555TruncZeroOf<T>;
880   this->template checkCastTo<F, T>({{XAAA, ZA}, {X555, Z5}},
881                                    {{ToMIN, 0}, {X555, ToMAX}});
882   // Use `if constexpr` here.
883   if (is_signed_v<F>) {
884     // One range
885     this->template checkCastTo<F, T>({{XAAA, ZA}}, {{XAAA, 0}});
886     // Two ranges
887     this->template checkCastTo<F, T>({{XAAA, ZA}, {1, 42}}, {{XAAA, 42}});
888   } else {
889     // One range
890     this->template checkCastTo<F, T>({{XAAA, ZA}}, {{0, 0}, {XAAA, ToMAX}});
891     // Two ranges
892     this->template checkCastTo<F, T>({{1, 42}, {XAAA, ZA}},
893                                      {{0, 42}, {XAAA, ToMAX}});
894   }
895   constexpr auto FromA = TV::FromA;
896   constexpr auto ToA = TV::ToA;
897   constexpr auto FromB = TV::FromB;
898   constexpr auto ToB = TV::ToB;
899   // int16 -> int8
900   // (0x00'01, 0x00'05)U(0xFF'01, 0xFF'05) casts to
901   // (0x01, 0x05)U(0x01, 0x05) unites to
902   // (0x01, 0x05)
903   this->template checkCastTo<F, T>({{FromA, ToA}, {FromB, ToB}},
904                                    {{FromA, ToA}});
905 }
906 
907 TYPED_TEST(RangeSetCastToConversionTest, Test) {
908   // Just to reduce the verbosity.
909   using F = typename TypeParam::FromType; // From
910   using T = typename TypeParam::ToType;   // To
911 
912   using TV = TestValues<F>;
913   constexpr auto MIN = TV::MIN;
914   constexpr auto MAX = TV::MAX;
915   constexpr auto MID = TV::MID;
916   constexpr auto B = TV::B;
917   constexpr auto C = TV::C;
918   // One point
919   this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}});
920   this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}});
921   this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}});
922   this->template checkCastTo<F, T>({{B, B}}, {{B, B}});
923   this->template checkCastTo<F, T>({{C, C}}, {{C, C}});
924   // Two points
925   this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, {{MAX, MIN}});
926   this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}},
927                                    {{MID, MID}, {MAX, MAX}});
928   this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}});
929   this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}});
930   this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}});
931   this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}});
932   this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}});
933   // One range
934   constexpr auto ToMIN = TestValues<T>::MIN;
935   constexpr auto ToMAX = TestValues<T>::MAX;
936   this->template checkCastTo<F, T>({{MIN, MAX}}, {{ToMIN, ToMAX}});
937   this->template checkCastTo<F, T>({{MIN, MID}},
938                                    {{ToMIN, ToMIN}, {MIN, ToMAX}});
939   this->template checkCastTo<F, T>({{MID, MAX}}, {{MID, MAX}});
940   this->template checkCastTo<F, T>({{B, MAX}}, {{ToMIN, MAX}, {B, ToMAX}});
941   this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}});
942   this->template checkCastTo<F, T>({{MIN, C}}, {{ToMIN, C}, {MIN, ToMAX}});
943   this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}});
944   this->template checkCastTo<F, T>({{B, C}}, {{ToMIN, C}, {B, ToMAX}});
945   // Two ranges
946   this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{C, B}});
947   this->template checkCastTo<F, T>({{B, MID}, {C, MAX}},
948                                    {{MID, MID}, {C, MAX}, {B, ToMAX}});
949   this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{MID, C}, {MIN, B}});
950 }
951 
952 TYPED_TEST(RangeSetCastToPromotionConversionTest, Test) {
953   // Just to reduce the verbosity.
954   using F = typename TypeParam::FromType; // From
955   using T = typename TypeParam::ToType;   // To
956 
957   using TV = TestValues<F>;
958   constexpr auto MIN = TV::MIN;
959   constexpr auto MAX = TV::MAX;
960   constexpr auto MID = TV::MID;
961   constexpr auto B = TV::B;
962   constexpr auto C = TV::C;
963   // One point
964   this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}});
965   this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}});
966   this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}});
967   this->template checkCastTo<F, T>({{B, B}}, {{B, B}});
968   this->template checkCastTo<F, T>({{C, C}}, {{C, C}});
969   // Two points
970   this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}},
971                                    {{MAX, MAX}, {MIN, MIN}});
972   this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}});
973   this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}},
974                                    {{MID, MID}, {MAX, MAX}});
975   this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}});
976   this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}});
977   this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}});
978   this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}});
979 
980   // Use `if constexpr` here.
981   if (is_signed_v<F>) {
982     // One range
983     this->template checkCastTo<F, T>({{MIN, MAX}}, {{0, MAX}, {MIN, -1}});
984     this->template checkCastTo<F, T>({{MIN, MID}}, {{0, 0}, {MIN, -1}});
985     this->template checkCastTo<F, T>({{MID, MAX}}, {{0, MAX}});
986     this->template checkCastTo<F, T>({{B, MAX}}, {{0, MAX}, {B, -1}});
987     this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}});
988     this->template checkCastTo<F, T>({{MIN, C}}, {{0, C}, {MIN, -1}});
989     this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}});
990     this->template checkCastTo<F, T>({{B, C}}, {{0, C}, {B, -1}});
991     // Two ranges
992     this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}},
993                                      {{C, MAX}, {MIN, B}});
994     this->template checkCastTo<F, T>({{B, MID}, {C, MAX}},
995                                      {{0, 0}, {C, MAX}, {B, -1}});
996     this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{0, C}, {MIN, B}});
997   } else {
998     // One range
999     this->template checkCastTo<F, T>({{MIN, MAX}}, {{MIN, MAX}});
1000     this->template checkCastTo<F, T>({{MIN, MID}}, {{MIN, MID}});
1001     this->template checkCastTo<F, T>({{MID, MAX}}, {{MID, MAX}});
1002     this->template checkCastTo<F, T>({{B, MAX}}, {{B, MAX}});
1003     this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}});
1004     this->template checkCastTo<F, T>({{MIN, C}}, {{MIN, C}});
1005     this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}});
1006     this->template checkCastTo<F, T>({{B, C}}, {{B, C}});
1007     // Two ranges
1008     this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}},
1009                                      {{MIN, B}, {C, MAX}});
1010     this->template checkCastTo<F, T>({{B, MID}, {C, MAX}},
1011                                      {{B, MID}, {C, MAX}});
1012     this->template checkCastTo<F, T>({{MIN, B}, {MID, C}},
1013                                      {{MIN, B}, {MID, C}});
1014   }
1015 }
1016 
1017 TYPED_TEST(RangeSetCastToTruncationConversionTest, Test) {
1018   // Just to reduce the verbosity.
1019   using F = typename TypeParam::FromType; // From
1020   using T = typename TypeParam::ToType;   // To
1021 
1022   using TV = TestValues<F>;
1023   constexpr auto MIN = TV::MIN;
1024   constexpr auto MAX = TV::MAX;
1025   constexpr auto MID = TV::MID;
1026   constexpr auto B = TV::B;
1027   constexpr auto C = TV::C;
1028   // One point
1029   this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}});
1030   this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}});
1031   this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}});
1032   this->template checkCastTo<F, T>({{B, B}}, {{B, B}});
1033   this->template checkCastTo<F, T>({{C, C}}, {{C, C}});
1034   // Two points
1035   // Use `if constexpr` here.
1036   if (is_signed_v<F>) {
1037     this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}},
1038                                      {{MIN, MIN}, {MAX, MAX}});
1039     this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}},
1040                                      {{MID, MID}, {MAX, MAX}});
1041   } else {
1042     this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, {{MAX, MIN}});
1043     this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}}, {{MAX, MIN}});
1044   }
1045   this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}});
1046   this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}});
1047   this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}});
1048   this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}});
1049   this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}});
1050   // One range
1051   constexpr auto ToMIN = TestValues<T>::MIN;
1052   constexpr auto ToMAX = TestValues<T>::MAX;
1053   this->template checkCastTo<F, T>({{MIN, MAX}}, {{ToMIN, ToMAX}});
1054   this->template checkCastTo<F, T>({{MIN, MID}}, {{ToMIN, ToMAX}});
1055   this->template checkCastTo<F, T>({{MID, MAX}}, {{ToMIN, ToMAX}});
1056   this->template checkCastTo<F, T>({{B, MAX}}, {{ToMIN, ToMAX}});
1057   this->template checkCastTo<F, T>({{C, MAX}}, {{ToMIN, ToMAX}});
1058   this->template checkCastTo<F, T>({{MIN, C}}, {{ToMIN, ToMAX}});
1059   this->template checkCastTo<F, T>({{MIN, B}}, {{ToMIN, ToMAX}});
1060   this->template checkCastTo<F, T>({{B, C}}, {{ToMIN, ToMAX}});
1061   // Two ranges
1062   this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{ToMIN, ToMAX}});
1063   this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, {{ToMIN, ToMAX}});
1064   this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{ToMIN, ToMAX}});
1065   constexpr auto XAAA = TV::XAAA;
1066   constexpr auto X555 = TV::X555;
1067   constexpr auto ZA = TV::template XAAATruncZeroOf<T>;
1068   constexpr auto Z5 = TV::template X555TruncZeroOf<T>;
1069   this->template checkCastTo<F, T>({{XAAA, ZA}, {X555, Z5}},
1070                                    {{ToMIN, 0}, {X555, ToMAX}});
1071   // Use `if constexpr` here.
1072   if (is_signed_v<F>) {
1073     // One range
1074     this->template checkCastTo<F, T>({{XAAA, ZA}}, {{0, 0}, {XAAA, ToMAX}});
1075     // Two ranges
1076     this->template checkCastTo<F, T>({{XAAA, ZA}, {1, 42}},
1077                                      {{0, 42}, {XAAA, ToMAX}});
1078   } else {
1079     // One range
1080     this->template checkCastTo<F, T>({{XAAA, ZA}}, {{XAAA, 0}});
1081     // Two ranges
1082     this->template checkCastTo<F, T>({{1, 42}, {XAAA, ZA}}, {{XAAA, 42}});
1083   }
1084   constexpr auto FromA = TV::FromA;
1085   constexpr auto ToA = TV::ToA;
1086   constexpr auto FromB = TV::FromB;
1087   constexpr auto ToB = TV::ToB;
1088   this->template checkCastTo<F, T>({{FromA, ToA}, {FromB, ToB}},
1089                                    {{FromA, ToA}});
1090 }
1091 
1092 } // namespace
1093