brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.1 KiB · 0df8b9f Raw
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