xref: /llvm-project/llvm/unittests/Support/Casting.cpp (revision 8fdec5d3badb94807d757c0c58a3900704320919)
1 //===---------- llvm/unittest/Support/Casting.cpp - Casting tests ---------===//
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 "llvm/Support/Casting.h"
10 #include "llvm/IR/User.h"
11 #include "llvm/Support/Debug.h"
12 #include "llvm/Support/raw_ostream.h"
13 #include "gtest/gtest.h"
14 #include <cstdlib>
15 
16 namespace llvm {
17 // Used to test illegal cast. If a cast doesn't match any of the "real" ones,
18 // it will match this one.
19 struct IllegalCast;
cast(...)20 template <typename T> IllegalCast *cast(...) { return nullptr; }
21 
22 // set up two example classes
23 // with conversion facility
24 //
25 struct bar {
barllvm::bar26   bar() {}
27   struct foo *baz();
28   struct foo *caz();
29   struct foo *daz();
30   struct foo *naz();
31 
32 private:
33   bar(const bar &);
34 };
35 struct foo {
foollvm::foo36   foo(const bar &) {}
37   void ext() const;
38 };
39 
40 struct base {
~basellvm::base41   virtual ~base() {}
42 };
43 
44 struct derived : public base {
classofllvm::derived45   static bool classof(const base *B) { return true; }
46 };
47 
48 struct derived_nocast : public base {
classofllvm::derived_nocast49   static bool classof(const base *B) { return false; }
50 };
51 
52 template <> struct isa_impl<foo, bar> {
doitllvm::isa_impl53   static inline bool doit(const bar &Val) {
54     dbgs() << "Classof: " << &Val << "\n";
55     return true;
56   }
57 };
58 
59 // Note for the future - please don't do this. isa_impl is an internal template
60 // for the implementation of `isa` and should not be exposed this way.
61 // Completely unrelated types *should* result in compiler errors if you try to
62 // cast between them.
63 template <typename T> struct isa_impl<foo, T> {
doitllvm::isa_impl64   static inline bool doit(const T &Val) { return false; }
65 };
66 
baz()67 foo *bar::baz() { return cast<foo>(this); }
68 
caz()69 foo *bar::caz() { return cast_or_null<foo>(this); }
70 
daz()71 foo *bar::daz() { return dyn_cast<foo>(this); }
72 
naz()73 foo *bar::naz() { return dyn_cast_or_null<foo>(this); }
74 
75 bar *fub();
76 
77 template <> struct simplify_type<foo> {
78   typedef int SimpleType;
getSimplifiedValuellvm::simplify_type79   static SimpleType getSimplifiedValue(foo &Val) { return 0; }
80 };
81 
82 struct T1 {};
83 
84 struct T2 {
T2llvm::T285   T2(const T1 &x) {}
classofllvm::T286   static bool classof(const T1 *x) { return true; }
87 };
88 
89 template <> struct CastInfo<T2, T1> : public OptionalValueCast<T2, T1> {};
90 
91 struct T3 {
T3llvm::T392   T3(const T1 *x) : hasValue(x != nullptr) {}
93 
classofllvm::T394   static bool classof(const T1 *x) { return true; }
95   bool hasValue = false;
96 };
97 
98 // T3 is convertible from a pointer to T1.
99 template <> struct CastInfo<T3, T1 *> : public ValueFromPointerCast<T3, T1> {};
100 
101 struct T4 {
T4llvm::T4102   T4() : hasValue(false) {}
T4llvm::T4103   T4(const T3 &x) : hasValue(true) {}
104 
classofllvm::T4105   static bool classof(const T3 *x) { return true; }
106   bool hasValue = false;
107 };
108 
109 template <> struct ValueIsPresent<T3> {
110   using UnwrappedType = T3;
isPresentllvm::ValueIsPresent111   static inline bool isPresent(const T3 &t) { return t.hasValue; }
unwrapValuellvm::ValueIsPresent112   static inline const T3 &unwrapValue(const T3 &t) { return t; }
113 };
114 
115 template <> struct CastInfo<T4, T3> {
116   using CastResultType = T4;
doCastllvm::CastInfo117   static inline CastResultType doCast(const T3 &t) { return T4(t); }
castFailedllvm::CastInfo118   static inline CastResultType castFailed() { return CastResultType(); }
doCastIfPossiblellvm::CastInfo119   static inline CastResultType doCastIfPossible(const T3 &f) {
120     return doCast(f);
121   }
122 };
123 
124 } // namespace llvm
125 
126 using namespace llvm;
127 
128 // Test the peculiar behavior of Use in simplify_type.
129 static_assert(std::is_same_v<simplify_type<Use>::SimpleType, Value *>,
130               "Use doesn't simplify correctly!");
131 static_assert(std::is_same_v<simplify_type<Use *>::SimpleType, Value *>,
132               "Use doesn't simplify correctly!");
133 
134 // Test that a regular class behaves as expected.
135 static_assert(std::is_same_v<simplify_type<foo>::SimpleType, int>,
136               "Unexpected simplify_type result!");
137 static_assert(std::is_same_v<simplify_type<foo *>::SimpleType, foo *>,
138               "Unexpected simplify_type result!");
139 
140 namespace {
141 
142 const foo *null_foo = nullptr;
143 
144 bar B;
145 extern bar &B1;
146 bar &B1 = B;
147 extern const bar *B2;
148 // test various configurations of const
149 const bar &B3 = B1;
150 const bar *const B4 = B2;
151 
TEST(CastingTest,isa)152 TEST(CastingTest, isa) {
153   EXPECT_TRUE(isa<foo>(B1));
154   EXPECT_TRUE(isa<foo>(B2));
155   EXPECT_TRUE(isa<foo>(B3));
156   EXPECT_TRUE(isa<foo>(B4));
157 }
158 
TEST(CastingTest,isa_and_nonnull)159 TEST(CastingTest, isa_and_nonnull) {
160   EXPECT_TRUE(isa_and_nonnull<foo>(B2));
161   EXPECT_TRUE(isa_and_nonnull<foo>(B4));
162   EXPECT_FALSE(isa_and_nonnull<foo>(fub()));
163 }
164 
TEST(CastingTest,cast)165 TEST(CastingTest, cast) {
166   foo &F1 = cast<foo>(B1);
167   EXPECT_NE(&F1, null_foo);
168   const foo *F3 = cast<foo>(B2);
169   EXPECT_NE(F3, null_foo);
170   const foo *F4 = cast<foo>(B2);
171   EXPECT_NE(F4, null_foo);
172   const foo &F5 = cast<foo>(B3);
173   EXPECT_NE(&F5, null_foo);
174   const foo *F6 = cast<foo>(B4);
175   EXPECT_NE(F6, null_foo);
176   // Can't pass null pointer to cast<>.
177   // foo *F7 = cast<foo>(fub());
178   // EXPECT_EQ(F7, null_foo);
179   foo *F8 = B1.baz();
180   EXPECT_NE(F8, null_foo);
181 
182   std::unique_ptr<const bar> BP(B2);
183   auto FP = cast<foo>(std::move(BP));
184   static_assert(std::is_same_v<std::unique_ptr<const foo>, decltype(FP)>,
185                 "Incorrect deduced return type!");
186   EXPECT_NE(FP.get(), null_foo);
187   FP.release();
188 }
189 
TEST(CastingTest,cast_or_null)190 TEST(CastingTest, cast_or_null) {
191   const foo *F11 = cast_or_null<foo>(B2);
192   EXPECT_NE(F11, null_foo);
193   const foo *F12 = cast_or_null<foo>(B2);
194   EXPECT_NE(F12, null_foo);
195   const foo *F13 = cast_or_null<foo>(B4);
196   EXPECT_NE(F13, null_foo);
197   const foo *F14 = cast_or_null<foo>(fub()); // Shouldn't print.
198   EXPECT_EQ(F14, null_foo);
199   foo *F15 = B1.caz();
200   EXPECT_NE(F15, null_foo);
201 
202   std::unique_ptr<const bar> BP(fub());
203   auto FP = cast_or_null<foo>(std::move(BP));
204   EXPECT_EQ(FP.get(), null_foo);
205 }
206 
TEST(CastingTest,dyn_cast)207 TEST(CastingTest, dyn_cast) {
208   const foo *F1 = dyn_cast<foo>(B2);
209   EXPECT_NE(F1, null_foo);
210   const foo *F2 = dyn_cast<foo>(B2);
211   EXPECT_NE(F2, null_foo);
212   const foo *F3 = dyn_cast<foo>(B4);
213   EXPECT_NE(F3, null_foo);
214   // Can't pass null pointer to dyn_cast<>.
215   // foo *F4 = dyn_cast<foo>(fub());
216   // EXPECT_EQ(F4, null_foo);
217   foo *F5 = B1.daz();
218   EXPECT_NE(F5, null_foo);
219 
220   auto BP = std::make_unique<const bar>();
221   auto FP = dyn_cast<foo>(BP);
222   static_assert(std::is_same_v<std::unique_ptr<const foo>, decltype(FP)>,
223                 "Incorrect deduced return type!");
224   EXPECT_NE(FP.get(), nullptr);
225   EXPECT_EQ(BP.get(), nullptr);
226 
227   auto BP2 = std::make_unique<base>();
228   auto DP = dyn_cast<derived_nocast>(BP2);
229   EXPECT_EQ(DP.get(), nullptr);
230   EXPECT_NE(BP2.get(), nullptr);
231 }
232 
233 // All these tests forward to dyn_cast_if_present, so they also provde an
234 // effective test for its use cases.
TEST(CastingTest,dyn_cast_or_null)235 TEST(CastingTest, dyn_cast_or_null) {
236   const foo *F1 = dyn_cast_or_null<foo>(B2);
237   EXPECT_NE(F1, null_foo);
238   const foo *F2 = dyn_cast_or_null<foo>(B2);
239   EXPECT_NE(F2, null_foo);
240   const foo *F3 = dyn_cast_or_null<foo>(B4);
241   EXPECT_NE(F3, null_foo);
242   foo *F4 = dyn_cast_or_null<foo>(fub());
243   EXPECT_EQ(F4, null_foo);
244   foo *F5 = B1.naz();
245   EXPECT_NE(F5, null_foo);
246   // dyn_cast_if_present should have exactly the same behavior as
247   // dyn_cast_or_null.
248   const foo *F6 = dyn_cast_if_present<foo>(B2);
249   EXPECT_EQ(F6, F2);
250 }
251 
TEST(CastingTest,dyn_cast_value_types)252 TEST(CastingTest, dyn_cast_value_types) {
253   T1 t1;
254   std::optional<T2> t2 = dyn_cast<T2>(t1);
255   EXPECT_TRUE(t2);
256 
257   T2 *t2ptr = dyn_cast<T2>(&t1);
258   EXPECT_TRUE(t2ptr != nullptr);
259 
260   T3 t3 = dyn_cast<T3>(&t1);
261   EXPECT_TRUE(t3.hasValue);
262 }
263 
TEST(CastingTest,dyn_cast_if_present)264 TEST(CastingTest, dyn_cast_if_present) {
265   std::optional<T1> empty{};
266   std::optional<T2> F1 = dyn_cast_if_present<T2>(empty);
267   EXPECT_FALSE(F1.has_value());
268 
269   T1 t1;
270   std::optional<T2> F2 = dyn_cast_if_present<T2>(t1);
271   EXPECT_TRUE(F2.has_value());
272 
273   T1 *t1Null = nullptr;
274 
275   // T3 should have hasValue == false because t1Null is nullptr.
276   T3 t3 = dyn_cast_if_present<T3>(t1Null);
277   EXPECT_FALSE(t3.hasValue);
278 
279   // Now because of that, T4 should receive the castFailed implementation of its
280   // FallibleCastTraits, which default-constructs a T4, which has no value.
281   T4 t4 = dyn_cast_if_present<T4>(t3);
282   EXPECT_FALSE(t4.hasValue);
283 }
284 
TEST(CastingTest,isa_check_predicates)285 TEST(CastingTest, isa_check_predicates) {
286   auto IsaFoo = IsaPred<foo>;
287   EXPECT_TRUE(IsaFoo(B1));
288   EXPECT_TRUE(IsaFoo(B2));
289   EXPECT_TRUE(IsaFoo(B3));
290   EXPECT_TRUE(IsaPred<foo>(B4));
291   EXPECT_TRUE((IsaPred<foo, bar>(B4)));
292 
293   auto IsaAndPresentFoo = IsaAndPresentPred<foo>;
294   EXPECT_TRUE(IsaAndPresentFoo(B2));
295   EXPECT_TRUE(IsaAndPresentFoo(B4));
296   EXPECT_FALSE(IsaAndPresentPred<foo>(fub()));
297   EXPECT_FALSE((IsaAndPresentPred<foo, bar>(fub())));
298 }
299 
newd()300 std::unique_ptr<derived> newd() { return std::make_unique<derived>(); }
newb()301 std::unique_ptr<base> newb() { return std::make_unique<derived>(); }
302 
TEST(CastingTest,unique_dyn_cast)303 TEST(CastingTest, unique_dyn_cast) {
304   derived *OrigD = nullptr;
305   auto D = std::make_unique<derived>();
306   OrigD = D.get();
307 
308   // Converting from D to itself is valid, it should return a new unique_ptr
309   // and the old one should become nullptr.
310   auto NewD = unique_dyn_cast<derived>(D);
311   ASSERT_EQ(OrigD, NewD.get());
312   ASSERT_EQ(nullptr, D);
313 
314   // Converting from D to B is valid, B should have a value and D should be
315   // nullptr.
316   auto B = unique_dyn_cast<base>(NewD);
317   ASSERT_EQ(OrigD, B.get());
318   ASSERT_EQ(nullptr, NewD);
319 
320   // Converting from B to itself is valid, it should return a new unique_ptr
321   // and the old one should become nullptr.
322   auto NewB = unique_dyn_cast<base>(B);
323   ASSERT_EQ(OrigD, NewB.get());
324   ASSERT_EQ(nullptr, B);
325 
326   // Converting from B to D is valid, D should have a value and B should be
327   // nullptr;
328   D = unique_dyn_cast<derived>(NewB);
329   ASSERT_EQ(OrigD, D.get());
330   ASSERT_EQ(nullptr, NewB);
331 
332   // This is a very contrived test, casting between completely unrelated types
333   // should generally fail to compile. See the classof shenanigans we have in
334   // the definition of `foo` above.
335   auto F = unique_dyn_cast<foo>(D);
336   ASSERT_EQ(nullptr, F);
337   ASSERT_EQ(OrigD, D.get());
338 
339   // All of the above should also hold for temporaries.
340   auto D2 = unique_dyn_cast<derived>(newd());
341   EXPECT_NE(nullptr, D2);
342 
343   auto B2 = unique_dyn_cast<derived>(newb());
344   EXPECT_NE(nullptr, B2);
345 
346   auto B3 = unique_dyn_cast<base>(newb());
347   EXPECT_NE(nullptr, B3);
348 
349   // This is a very contrived test, casting between completely unrelated types
350   // should generally fail to compile. See the classof shenanigans we have in
351   // the definition of `foo` above.
352   auto F2 = unique_dyn_cast<foo>(newb());
353   EXPECT_EQ(nullptr, F2);
354 }
355 
356 // These lines are errors...
357 // foo *F20 = cast<foo>(B2);  // Yields const foo*
358 // foo &F21 = cast<foo>(B3);  // Yields const foo&
359 // foo *F22 = cast<foo>(B4);  // Yields const foo*
360 // foo &F23 = cast_or_null<foo>(B1);
361 // const foo &F24 = cast_or_null<foo>(B3);
362 
363 const bar *B2 = &B;
364 } // anonymous namespace
365 
fub()366 bar *llvm::fub() { return nullptr; }
367 
368 namespace {
369 namespace inferred_upcasting {
370 // This test case verifies correct behavior of inferred upcasts when the
371 // types are statically known to be OK to upcast. This is the case when,
372 // for example, Derived inherits from Base, and we do `isa<Base>(Derived)`.
373 
374 // Note: This test will actually fail to compile without inferred
375 // upcasting.
376 
377 class Base {
378 public:
379   // No classof. We are testing that the upcast is inferred.
Base()380   Base() {}
381 };
382 
383 class Derived : public Base {
384 public:
Derived()385   Derived() {}
386 };
387 
388 // Even with no explicit classof() in Base, we should still be able to cast
389 // Derived to its base class.
TEST(CastingTest,UpcastIsInferred)390 TEST(CastingTest, UpcastIsInferred) {
391   Derived D;
392   EXPECT_TRUE(isa<Base>(D));
393   Base *BP = dyn_cast<Base>(&D);
394   EXPECT_NE(BP, nullptr);
395 }
396 
397 // This test verifies that the inferred upcast takes precedence over an
398 // explicitly written one. This is important because it verifies that the
399 // dynamic check gets optimized away.
400 class UseInferredUpcast {
401 public:
402   int Dummy;
classof(const UseInferredUpcast *)403   static bool classof(const UseInferredUpcast *) { return false; }
404 };
405 
TEST(CastingTest,InferredUpcastTakesPrecedence)406 TEST(CastingTest, InferredUpcastTakesPrecedence) {
407   UseInferredUpcast UIU;
408   // Since the explicit classof() returns false, this will fail if the
409   // explicit one is used.
410   EXPECT_TRUE(isa<UseInferredUpcast>(&UIU));
411 }
412 
413 } // end namespace inferred_upcasting
414 } // end anonymous namespace
415 
416 namespace {
417 namespace pointer_wrappers {
418 
419 struct Base {
420   bool IsDerived;
Base__anon535cc0f40311::pointer_wrappers::Base421   Base(bool IsDerived = false) : IsDerived(IsDerived) {}
422 };
423 
424 struct Derived : Base {
Derived__anon535cc0f40311::pointer_wrappers::Derived425   Derived() : Base(true) {}
classof__anon535cc0f40311::pointer_wrappers::Derived426   static bool classof(const Base *B) { return B->IsDerived; }
427 };
428 
429 class PTy {
430   Base *B;
431 
432 public:
PTy(Base * B)433   PTy(Base *B) : B(B) {}
operator bool() const434   explicit operator bool() const { return get(); }
get() const435   Base *get() const { return B; }
436 };
437 
438 } // end namespace pointer_wrappers
439 } // end namespace
440 
441 namespace llvm {
442 
443 template <> struct ValueIsPresent<pointer_wrappers::PTy> {
444   using UnwrappedType = pointer_wrappers::PTy;
isPresentllvm::ValueIsPresent445   static inline bool isPresent(const pointer_wrappers::PTy &P) {
446     return P.get() != nullptr;
447   }
unwrapValuellvm::ValueIsPresent448   static UnwrappedType &unwrapValue(pointer_wrappers::PTy &P) { return P; }
449 };
450 
451 template <> struct ValueIsPresent<const pointer_wrappers::PTy> {
452   using UnwrappedType = pointer_wrappers::PTy;
isPresentllvm::ValueIsPresent453   static inline bool isPresent(const pointer_wrappers::PTy &P) {
454     return P.get() != nullptr;
455   }
456 
unwrapValuellvm::ValueIsPresent457   static UnwrappedType &unwrapValue(const pointer_wrappers::PTy &P) {
458     return const_cast<UnwrappedType &>(P);
459   }
460 };
461 
462 template <> struct simplify_type<pointer_wrappers::PTy> {
463   typedef pointer_wrappers::Base *SimpleType;
getSimplifiedValuellvm::simplify_type464   static SimpleType getSimplifiedValue(pointer_wrappers::PTy &P) {
465     return P.get();
466   }
467 };
468 template <> struct simplify_type<const pointer_wrappers::PTy> {
469   typedef pointer_wrappers::Base *SimpleType;
getSimplifiedValuellvm::simplify_type470   static SimpleType getSimplifiedValue(const pointer_wrappers::PTy &P) {
471     return P.get();
472   }
473 };
474 
475 } // end namespace llvm
476 
477 namespace {
478 namespace pointer_wrappers {
479 
480 // Some objects.
481 pointer_wrappers::Base B;
482 pointer_wrappers::Derived D;
483 
484 // Mutable "smart" pointers.
485 pointer_wrappers::PTy MN(nullptr);
486 pointer_wrappers::PTy MB(&B);
487 pointer_wrappers::PTy MD(&D);
488 
489 // Const "smart" pointers.
490 const pointer_wrappers::PTy CN(nullptr);
491 const pointer_wrappers::PTy CB(&B);
492 const pointer_wrappers::PTy CD(&D);
493 
TEST(CastingTest,smart_isa)494 TEST(CastingTest, smart_isa) {
495   EXPECT_TRUE(!isa<pointer_wrappers::Derived>(MB));
496   EXPECT_TRUE(!isa<pointer_wrappers::Derived>(CB));
497   EXPECT_TRUE(isa<pointer_wrappers::Derived>(MD));
498   EXPECT_TRUE(isa<pointer_wrappers::Derived>(CD));
499 }
500 
TEST(CastingTest,smart_cast)501 TEST(CastingTest, smart_cast) {
502   EXPECT_EQ(cast<pointer_wrappers::Derived>(MD), &D);
503   EXPECT_EQ(cast<pointer_wrappers::Derived>(CD), &D);
504 }
505 
TEST(CastingTest,smart_cast_or_null)506 TEST(CastingTest, smart_cast_or_null) {
507   EXPECT_EQ(cast_or_null<pointer_wrappers::Derived>(MN), nullptr);
508   EXPECT_EQ(cast_or_null<pointer_wrappers::Derived>(CN), nullptr);
509   EXPECT_EQ(cast_or_null<pointer_wrappers::Derived>(MD), &D);
510   EXPECT_EQ(cast_or_null<pointer_wrappers::Derived>(CD), &D);
511 }
512 
TEST(CastingTest,smart_dyn_cast)513 TEST(CastingTest, smart_dyn_cast) {
514   EXPECT_EQ(dyn_cast<pointer_wrappers::Derived>(MB), nullptr);
515   EXPECT_EQ(dyn_cast<pointer_wrappers::Derived>(CB), nullptr);
516   EXPECT_EQ(dyn_cast<pointer_wrappers::Derived>(MD), &D);
517   EXPECT_EQ(dyn_cast<pointer_wrappers::Derived>(CD), &D);
518 }
519 
TEST(CastingTest,smart_dyn_cast_or_null)520 TEST(CastingTest, smart_dyn_cast_or_null) {
521   EXPECT_EQ(dyn_cast_or_null<pointer_wrappers::Derived>(MN), nullptr);
522   EXPECT_EQ(dyn_cast_or_null<pointer_wrappers::Derived>(CN), nullptr);
523   EXPECT_EQ(dyn_cast_or_null<pointer_wrappers::Derived>(MB), nullptr);
524   EXPECT_EQ(dyn_cast_or_null<pointer_wrappers::Derived>(CB), nullptr);
525   EXPECT_EQ(dyn_cast_or_null<pointer_wrappers::Derived>(MD), &D);
526   EXPECT_EQ(dyn_cast_or_null<pointer_wrappers::Derived>(CD), &D);
527 }
528 
529 } // end namespace pointer_wrappers
530 
531 #ifndef NDEBUG
532 namespace assertion_checks {
533 struct Base {
~Base__anon535cc0f40411::assertion_checks::Base534   virtual ~Base() {}
535 };
536 
537 struct Derived : public Base {
classof__anon535cc0f40411::assertion_checks::Derived538   static bool classof(const Base *B) { return false; }
539 };
540 
TEST(CastingTest,assertion_check_const_ref)541 TEST(CastingTest, assertion_check_const_ref) {
542   const Base B;
543   EXPECT_DEATH((void)cast<Derived>(B), "argument of incompatible type")
544       << "Invalid cast of const ref did not cause an abort()";
545 }
546 
TEST(CastingTest,assertion_check_ref)547 TEST(CastingTest, assertion_check_ref) {
548   Base B;
549   EXPECT_DEATH((void)cast<Derived>(B), "argument of incompatible type")
550       << "Invalid cast of const ref did not cause an abort()";
551 }
552 
TEST(CastingTest,assertion_check_ptr)553 TEST(CastingTest, assertion_check_ptr) {
554   Base B;
555   EXPECT_DEATH((void)cast<Derived>(&B), "argument of incompatible type")
556       << "Invalid cast of const ref did not cause an abort()";
557 }
558 
TEST(CastingTest,assertion_check_unique_ptr)559 TEST(CastingTest, assertion_check_unique_ptr) {
560   auto B = std::make_unique<Base>();
561   EXPECT_DEATH((void)cast<Derived>(std::move(B)),
562                "argument of incompatible type")
563       << "Invalid cast of const ref did not cause an abort()";
564 }
565 
566 } // end namespace assertion_checks
567 #endif
568 } // end namespace
569