608 lines · cpp
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-exception6//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 16namespace llvm {17// Used to test illegal cast. If a cast doesn't match any of the "real" ones,18// it will match this one.19struct IllegalCast;20template <typename T> IllegalCast *cast(...) { return nullptr; }21 22// set up two example classes23// with conversion facility24//25struct bar {26 bar() = default;27 bar(const bar &) = delete;28 struct foo *baz();29 struct foo *caz();30 struct foo *daz();31 struct foo *naz();32};33struct foo {34 foo(const bar &) {}35 void ext() const;36};37 38struct base {39 virtual ~base() = default;40};41 42struct derived : public base {43 static bool classof(const base *B) { return true; }44};45 46struct derived_nocast : public base {47 static bool classof(const base *B) { return false; }48};49 50template <> struct isa_impl<foo, bar> {51 static inline bool doit(const bar &Val) {52 dbgs() << "Classof: " << &Val << "\n";53 return true;54 }55};56 57// Note for the future - please don't do this. isa_impl is an internal template58// for the implementation of `isa` and should not be exposed this way.59// Completely unrelated types *should* result in compiler errors if you try to60// cast between them.61template <typename T> struct isa_impl<foo, T> {62 static inline bool doit(const T &Val) { return false; }63};64 65foo *bar::baz() { return cast<foo>(this); }66 67foo *bar::caz() { return cast_or_null<foo>(this); }68 69foo *bar::daz() { return dyn_cast<foo>(this); }70 71foo *bar::naz() { return dyn_cast_or_null<foo>(this); }72 73bar *fub();74 75template <> struct simplify_type<foo> {76 typedef int SimpleType;77 static SimpleType getSimplifiedValue(foo &Val) { return 0; }78};79 80struct T1 {};81 82struct T2 {83 T2(const T1 &x) {}84 static bool classof(const T1 *x) { return true; }85};86 87template <> struct CastInfo<T2, T1> : public OptionalValueCast<T2, T1> {};88 89struct T3 {90 T3(const T1 *x) : hasValue(x != nullptr) {}91 92 static bool classof(const T1 *x) { return true; }93 bool hasValue = false;94};95 96// T3 is convertible from a pointer to T1.97template <> struct CastInfo<T3, T1 *> : public ValueFromPointerCast<T3, T1> {};98 99struct T4 {100 T4() : hasValue(false) {}101 T4(const T3 &x) : hasValue(true) {}102 103 static bool classof(const T3 *x) { return true; }104 bool hasValue = false;105};106 107template <> struct ValueIsPresent<T3> {108 using UnwrappedType = T3;109 static inline bool isPresent(const T3 &t) { return t.hasValue; }110 static inline const T3 &unwrapValue(const T3 &t) { return t; }111};112 113template <> struct CastInfo<T4, T3> {114 using CastResultType = T4;115 static inline CastResultType doCast(const T3 &t) { return T4(t); }116 static inline CastResultType castFailed() { return CastResultType(); }117 static inline CastResultType doCastIfPossible(const T3 &f) {118 return doCast(f);119 }120};121 122} // namespace llvm123 124using namespace llvm;125 126// Test the peculiar behavior of Use in simplify_type.127static_assert(std::is_same_v<simplify_type<Use>::SimpleType, Value *>,128 "Use doesn't simplify correctly!");129static_assert(std::is_same_v<simplify_type<Use *>::SimpleType, Value *>,130 "Use doesn't simplify correctly!");131 132// Test that a regular class behaves as expected.133static_assert(std::is_same_v<simplify_type<foo>::SimpleType, int>,134 "Unexpected simplify_type result!");135static_assert(std::is_same_v<simplify_type<foo *>::SimpleType, foo *>,136 "Unexpected simplify_type result!");137 138namespace {139 140const foo *null_foo = nullptr;141 142bar B;143extern bar &B1;144bar &B1 = B;145extern const bar *B2;146// test various configurations of const147const bar &B3 = B1;148const bar *const B4 = B2;149 150TEST(CastingTest, isa) {151 EXPECT_TRUE(isa<foo>(B1));152 EXPECT_TRUE(isa<foo>(B2));153 EXPECT_TRUE(isa<foo>(B3));154 EXPECT_TRUE(isa<foo>(B4));155}156 157TEST(CastingTest, isa_and_nonnull) {158 EXPECT_TRUE(isa_and_nonnull<foo>(B2));159 EXPECT_TRUE(isa_and_nonnull<foo>(B4));160 EXPECT_FALSE(isa_and_nonnull<foo>(fub()));161}162 163TEST(CastingTest, cast) {164 foo &F1 = cast<foo>(B1);165 EXPECT_NE(&F1, null_foo);166 const foo *F3 = cast<foo>(B2);167 EXPECT_NE(F3, null_foo);168 const foo *F4 = cast<foo>(B2);169 EXPECT_NE(F4, null_foo);170 const foo &F5 = cast<foo>(B3);171 EXPECT_NE(&F5, null_foo);172 const foo *F6 = cast<foo>(B4);173 EXPECT_NE(F6, null_foo);174 // Can't pass null pointer to cast<>.175 // foo *F7 = cast<foo>(fub());176 // EXPECT_EQ(F7, null_foo);177 foo *F8 = B1.baz();178 EXPECT_NE(F8, null_foo);179 180 std::unique_ptr<const bar> BP(B2);181 auto FP = cast<foo>(std::move(BP));182 static_assert(std::is_same_v<std::unique_ptr<const foo>, decltype(FP)>,183 "Incorrect deduced return type!");184 EXPECT_NE(FP.get(), null_foo);185 FP.release();186}187 188TEST(CastingTest, cast_or_null) {189 const foo *F11 = cast_or_null<foo>(B2);190 EXPECT_NE(F11, null_foo);191 const foo *F12 = cast_or_null<foo>(B2);192 EXPECT_NE(F12, null_foo);193 const foo *F13 = cast_or_null<foo>(B4);194 EXPECT_NE(F13, null_foo);195 const foo *F14 = cast_or_null<foo>(fub()); // Shouldn't print.196 EXPECT_EQ(F14, null_foo);197 foo *F15 = B1.caz();198 EXPECT_NE(F15, null_foo);199 200 std::unique_ptr<const bar> BP(fub());201 auto FP = cast_or_null<foo>(std::move(BP));202 EXPECT_EQ(FP.get(), null_foo);203}204 205TEST(CastingTest, dyn_cast) {206 const foo *F1 = dyn_cast<foo>(B2);207 EXPECT_NE(F1, null_foo);208 const foo *F2 = dyn_cast<foo>(B2);209 EXPECT_NE(F2, null_foo);210 const foo *F3 = dyn_cast<foo>(B4);211 EXPECT_NE(F3, null_foo);212 // Can't pass null pointer to dyn_cast<>.213 // foo *F4 = dyn_cast<foo>(fub());214 // EXPECT_EQ(F4, null_foo);215 foo *F5 = B1.daz();216 EXPECT_NE(F5, null_foo);217 218 auto BP = std::make_unique<const bar>();219 auto FP = dyn_cast<foo>(BP);220 static_assert(std::is_same_v<std::unique_ptr<const foo>, decltype(FP)>,221 "Incorrect deduced return type!");222 EXPECT_NE(FP.get(), nullptr);223 EXPECT_EQ(BP.get(), nullptr);224 225 auto BP2 = std::make_unique<base>();226 auto DP = dyn_cast<derived_nocast>(BP2);227 EXPECT_EQ(DP.get(), nullptr);228 EXPECT_NE(BP2.get(), nullptr);229}230 231// All these tests forward to dyn_cast_if_present, so they also provde an232// effective test for its use cases.233TEST(CastingTest, dyn_cast_or_null) {234 const foo *F1 = dyn_cast_or_null<foo>(B2);235 EXPECT_NE(F1, null_foo);236 const foo *F2 = dyn_cast_or_null<foo>(B2);237 EXPECT_NE(F2, null_foo);238 const foo *F3 = dyn_cast_or_null<foo>(B4);239 EXPECT_NE(F3, null_foo);240 foo *F4 = dyn_cast_or_null<foo>(fub());241 EXPECT_EQ(F4, null_foo);242 foo *F5 = B1.naz();243 EXPECT_NE(F5, null_foo);244 // dyn_cast_if_present should have exactly the same behavior as245 // dyn_cast_or_null.246 const foo *F6 = dyn_cast_if_present<foo>(B2);247 EXPECT_EQ(F6, F2);248}249 250TEST(CastingTest, dyn_cast_value_types) {251 T1 t1;252 std::optional<T2> t2 = dyn_cast<T2>(t1);253 EXPECT_TRUE(t2);254 255 T2 *t2ptr = dyn_cast<T2>(&t1);256 EXPECT_TRUE(t2ptr != nullptr);257 258 T3 t3 = dyn_cast<T3>(&t1);259 EXPECT_TRUE(t3.hasValue);260}261 262TEST(CastingTest, dyn_cast_if_present) {263 std::optional<T1> empty{};264 std::optional<T2> F1 = dyn_cast_if_present<T2>(empty);265 EXPECT_FALSE(F1.has_value());266 267 T1 t1;268 std::optional<T2> F2 = dyn_cast_if_present<T2>(t1);269 EXPECT_TRUE(F2.has_value());270 271 T1 *t1Null = nullptr;272 273 // T3 should have hasValue == false because t1Null is nullptr.274 T3 t3 = dyn_cast_if_present<T3>(t1Null);275 EXPECT_FALSE(t3.hasValue);276 277 // Now because of that, T4 should receive the castFailed implementation of its278 // FallibleCastTraits, which default-constructs a T4, which has no value.279 T4 t4 = dyn_cast_if_present<T4>(t3);280 EXPECT_FALSE(t4.hasValue);281}282 283TEST(CastingTest, isa_check_predicates) {284 auto IsaFoo = IsaPred<foo>;285 EXPECT_TRUE(IsaFoo(B1));286 EXPECT_TRUE(IsaFoo(B2));287 EXPECT_TRUE(IsaFoo(B3));288 EXPECT_TRUE(IsaPred<foo>(B4));289 EXPECT_TRUE((IsaPred<foo, bar>(B4)));290 291 auto IsaAndPresentFoo = IsaAndPresentPred<foo>;292 EXPECT_TRUE(IsaAndPresentFoo(B2));293 EXPECT_TRUE(IsaAndPresentFoo(B4));294 EXPECT_FALSE(IsaAndPresentPred<foo>(fub()));295 EXPECT_FALSE((IsaAndPresentPred<foo, bar>(fub())));296}297 298std::unique_ptr<derived> newd() { return std::make_unique<derived>(); }299std::unique_ptr<base> newb() { return std::make_unique<derived>(); }300 301TEST(CastingTest, unique_dyn_cast) {302 derived *OrigD = nullptr;303 auto D = std::make_unique<derived>();304 OrigD = D.get();305 306 // Converting from D to itself is valid, it should return a new unique_ptr307 // and the old one should become nullptr.308 auto NewD = unique_dyn_cast<derived>(D);309 ASSERT_EQ(OrigD, NewD.get());310 ASSERT_EQ(nullptr, D);311 312 // Converting from D to B is valid, B should have a value and D should be313 // nullptr.314 auto B = unique_dyn_cast<base>(NewD);315 ASSERT_EQ(OrigD, B.get());316 ASSERT_EQ(nullptr, NewD);317 318 // Converting from B to itself is valid, it should return a new unique_ptr319 // and the old one should become nullptr.320 auto NewB = unique_dyn_cast<base>(B);321 ASSERT_EQ(OrigD, NewB.get());322 ASSERT_EQ(nullptr, B);323 324 // Converting from B to D is valid, D should have a value and B should be325 // nullptr;326 D = unique_dyn_cast<derived>(NewB);327 ASSERT_EQ(OrigD, D.get());328 ASSERT_EQ(nullptr, NewB);329 330 // This is a very contrived test, casting between completely unrelated types331 // should generally fail to compile. See the classof shenanigans we have in332 // the definition of `foo` above.333 auto F = unique_dyn_cast<foo>(D);334 ASSERT_EQ(nullptr, F);335 ASSERT_EQ(OrigD, D.get());336 337 // All of the above should also hold for temporaries.338 auto D2 = unique_dyn_cast<derived>(newd());339 EXPECT_NE(nullptr, D2);340 341 auto B2 = unique_dyn_cast<derived>(newb());342 EXPECT_NE(nullptr, B2);343 344 auto B3 = unique_dyn_cast<base>(newb());345 EXPECT_NE(nullptr, B3);346 347 // This is a very contrived test, casting between completely unrelated types348 // should generally fail to compile. See the classof shenanigans we have in349 // the definition of `foo` above.350 auto F2 = unique_dyn_cast<foo>(newb());351 EXPECT_EQ(nullptr, F2);352}353 354// These lines are errors...355// foo *F20 = cast<foo>(B2); // Yields const foo*356// foo &F21 = cast<foo>(B3); // Yields const foo&357// foo *F22 = cast<foo>(B4); // Yields const foo*358// foo &F23 = cast_or_null<foo>(B1);359// const foo &F24 = cast_or_null<foo>(B3);360 361const bar *B2 = &B;362} // anonymous namespace363 364bar *llvm::fub() { return nullptr; }365 366namespace {367namespace inferred_upcasting {368// This test case verifies correct behavior of inferred upcasts when the369// types are statically known to be OK to upcast. This is the case when,370// for example, Derived inherits from Base, and we do `isa<Base>(Derived)`.371 372// Note: This test will actually fail to compile without inferred373// upcasting.374 375class Base {376public:377 // No classof. We are testing that the upcast is inferred.378 Base() = default;379};380 381class Derived : public Base {382public:383 Derived() = default;384};385 386// Even with no explicit classof() in Base, we should still be able to cast387// Derived to its base class.388TEST(CastingTest, UpcastIsInferred) {389 Derived D;390 EXPECT_TRUE(isa<Base>(D));391 Base *BP = dyn_cast<Base>(&D);392 EXPECT_NE(BP, nullptr);393}394 395// This test verifies that the inferred upcast takes precedence over an396// explicitly written one. This is important because it verifies that the397// dynamic check gets optimized away.398class UseInferredUpcast {399public:400 int Dummy;401 static bool classof(const UseInferredUpcast *) { return false; }402};403 404TEST(CastingTest, InferredUpcastTakesPrecedence) {405 UseInferredUpcast UIU;406 // Since the explicit classof() returns false, this will fail if the407 // explicit one is used.408 EXPECT_TRUE(isa<UseInferredUpcast>(&UIU));409}410 411} // end namespace inferred_upcasting412} // end anonymous namespace413 414namespace {415namespace pointer_wrappers {416 417struct Base {418 bool IsDerived;419 Base(bool IsDerived = false) : IsDerived(IsDerived) {}420};421 422struct Derived : Base {423 Derived() : Base(true) {}424 static bool classof(const Base *B) { return B->IsDerived; }425};426 427class PTy {428 Base *B;429 430public:431 PTy(Base *B) : B(B) {}432 explicit operator bool() const { return get(); }433 Base *get() const { return B; }434};435 436} // end namespace pointer_wrappers437} // end namespace438 439namespace llvm {440 441template <> struct ValueIsPresent<pointer_wrappers::PTy> {442 using UnwrappedType = pointer_wrappers::PTy;443 static inline bool isPresent(const pointer_wrappers::PTy &P) {444 return P.get() != nullptr;445 }446 static UnwrappedType &unwrapValue(pointer_wrappers::PTy &P) { return P; }447};448 449template <> struct ValueIsPresent<const pointer_wrappers::PTy> {450 using UnwrappedType = pointer_wrappers::PTy;451 static inline bool isPresent(const pointer_wrappers::PTy &P) {452 return P.get() != nullptr;453 }454 455 static UnwrappedType &unwrapValue(const pointer_wrappers::PTy &P) {456 return const_cast<UnwrappedType &>(P);457 }458};459 460template <> struct simplify_type<pointer_wrappers::PTy> {461 typedef pointer_wrappers::Base *SimpleType;462 static SimpleType getSimplifiedValue(pointer_wrappers::PTy &P) {463 return P.get();464 }465};466template <> struct simplify_type<const pointer_wrappers::PTy> {467 typedef pointer_wrappers::Base *SimpleType;468 static SimpleType getSimplifiedValue(const pointer_wrappers::PTy &P) {469 return P.get();470 }471};472 473} // end namespace llvm474 475namespace {476namespace pointer_wrappers {477 478// Some objects.479pointer_wrappers::Base B;480pointer_wrappers::Derived D;481 482// Mutable "smart" pointers.483pointer_wrappers::PTy MN(nullptr);484pointer_wrappers::PTy MB(&B);485pointer_wrappers::PTy MD(&D);486 487// Const "smart" pointers.488const pointer_wrappers::PTy CN(nullptr);489const pointer_wrappers::PTy CB(&B);490const pointer_wrappers::PTy CD(&D);491 492TEST(CastingTest, smart_isa) {493 EXPECT_TRUE(!isa<pointer_wrappers::Derived>(MB));494 EXPECT_TRUE(!isa<pointer_wrappers::Derived>(CB));495 EXPECT_TRUE(isa<pointer_wrappers::Derived>(MD));496 EXPECT_TRUE(isa<pointer_wrappers::Derived>(CD));497}498 499TEST(CastingTest, smart_cast) {500 EXPECT_EQ(cast<pointer_wrappers::Derived>(MD), &D);501 EXPECT_EQ(cast<pointer_wrappers::Derived>(CD), &D);502}503 504TEST(CastingTest, smart_cast_or_null) {505 EXPECT_EQ(cast_or_null<pointer_wrappers::Derived>(MN), nullptr);506 EXPECT_EQ(cast_or_null<pointer_wrappers::Derived>(CN), nullptr);507 EXPECT_EQ(cast_or_null<pointer_wrappers::Derived>(MD), &D);508 EXPECT_EQ(cast_or_null<pointer_wrappers::Derived>(CD), &D);509}510 511TEST(CastingTest, smart_dyn_cast) {512 EXPECT_EQ(dyn_cast<pointer_wrappers::Derived>(MB), nullptr);513 EXPECT_EQ(dyn_cast<pointer_wrappers::Derived>(CB), nullptr);514 EXPECT_EQ(dyn_cast<pointer_wrappers::Derived>(MD), &D);515 EXPECT_EQ(dyn_cast<pointer_wrappers::Derived>(CD), &D);516}517 518TEST(CastingTest, smart_dyn_cast_or_null) {519 EXPECT_EQ(dyn_cast_or_null<pointer_wrappers::Derived>(MN), nullptr);520 EXPECT_EQ(dyn_cast_or_null<pointer_wrappers::Derived>(CN), nullptr);521 EXPECT_EQ(dyn_cast_or_null<pointer_wrappers::Derived>(MB), nullptr);522 EXPECT_EQ(dyn_cast_or_null<pointer_wrappers::Derived>(CB), nullptr);523 EXPECT_EQ(dyn_cast_or_null<pointer_wrappers::Derived>(MD), &D);524 EXPECT_EQ(dyn_cast_or_null<pointer_wrappers::Derived>(CD), &D);525}526 527} // end namespace pointer_wrappers528 529#ifndef NDEBUG530namespace assertion_checks {531struct Base {532 virtual ~Base() = default;533};534 535struct Derived : public Base {536 static bool classof(const Base *B) { return false; }537};538 539TEST(CastingTest, assertion_check_const_ref) {540 const Base B;541 EXPECT_DEATH((void)cast<Derived>(B), "argument of incompatible type")542 << "Invalid cast of const ref did not cause an abort()";543}544 545TEST(CastingTest, assertion_check_ref) {546 Base B;547 EXPECT_DEATH((void)cast<Derived>(B), "argument of incompatible type")548 << "Invalid cast of const ref did not cause an abort()";549}550 551TEST(CastingTest, assertion_check_ptr) {552 Base B;553 EXPECT_DEATH((void)cast<Derived>(&B), "argument of incompatible type")554 << "Invalid cast of const ref did not cause an abort()";555}556 557TEST(CastingTest, assertion_check_unique_ptr) {558 auto B = std::make_unique<Base>();559 EXPECT_DEATH((void)cast<Derived>(std::move(B)),560 "argument of incompatible type")561 << "Invalid cast of const ref did not cause an abort()";562}563 564TEST(Casting, StaticCastPredicate) {565 uint32_t Value = 1;566 567 static_assert(568 std::is_same_v<decltype(StaticCastTo<uint64_t>(Value)), uint64_t>);569}570 571TEST(Casting, LLVMRTTIPredicates) {572 struct Base {573 enum Kind { BK_Base, BK_Derived };574 const Kind K;575 Base(Kind K = BK_Base) : K(K) {}576 Kind getKind() const { return K; }577 virtual ~Base() = default;578 };579 580 struct Derived : Base {581 Derived() : Base(BK_Derived) {}582 static bool classof(const Base *B) { return B->getKind() == BK_Derived; }583 bool Field = false;584 };585 586 Base B;587 Derived D;588 Base *BD = &D;589 Base *Null = nullptr;590 591 // Pointers.592 EXPECT_EQ(DynCastTo<Derived>(BD), &D);593 EXPECT_EQ(CastTo<Derived>(BD), &D);594 EXPECT_EQ(DynCastTo<Derived>(&B), nullptr);595 EXPECT_EQ(CastIfPresentTo<Derived>(BD), &D);596 EXPECT_EQ(CastIfPresentTo<Derived>(Null), nullptr);597 EXPECT_EQ(DynCastIfPresentTo<Derived>(BD), &D);598 EXPECT_EQ(DynCastIfPresentTo<Derived>(Null), nullptr);599 600 Base &R = D;601 CastTo<Derived>(R).Field = true;602 EXPECT_TRUE(D.Field);603}604 605} // end namespace assertion_checks606#endif607} // end namespace608