llvm/llvm/unittests/Support/Casting.cpp

//===---------- llvm/unittest/Support/Casting.cpp - Casting tests ---------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/Casting.h"
#include "llvm/IR/User.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
#include <cstdlib>

namespace llvm {
// Used to test illegal cast. If a cast doesn't match any of the "real" ones,
// it will match this one.
struct IllegalCast;
template <typename T> IllegalCast *cast(...) {}

// set up two example classes
// with conversion facility
//
struct bar {};
struct foo {};

struct base {};

struct derived : public base {};

struct derived_nocast : public base {};

template <> struct isa_impl<foo, bar> {};

// Note for the future - please don't do this. isa_impl is an internal template
// for the implementation of `isa` and should not be exposed this way.
// Completely unrelated types *should* result in compiler errors if you try to
// cast between them.
isa_impl<foo, T>;

foo *bar::baz() {}

foo *bar::caz() {}

foo *bar::daz() {}

foo *bar::naz() {}

bar *fub();

template <> struct simplify_type<foo> {};

struct T1 {};

struct T2 {};

template <> struct CastInfo<T2, T1> : public OptionalValueCast<T2, T1> {};

struct T3 {};

// T3 is convertible from a pointer to T1.
template <> struct CastInfo<T3, T1 *> : public ValueFromPointerCast<T3, T1> {};

struct T4 {};

template <> struct ValueIsPresent<T3> {};

template <> struct CastInfo<T4, T3> {};

} // namespace llvm

usingnamespacellvm;

// Test the peculiar behavior of Use in simplify_type.
static_assert;
static_assert;

// Test that a regular class behaves as expected.
static_assert;
static_assert;

namespace {

const foo *null_foo =;

bar B;
extern bar &B1;
bar &B1 =;
extern const bar *B2;
// test various configurations of const
const bar &B3 =;
const bar *const B4 =;

TEST(CastingTest, isa) {}

TEST(CastingTest, isa_and_nonnull) {}

TEST(CastingTest, cast) {}

TEST(CastingTest, cast_or_null) {}

TEST(CastingTest, dyn_cast) {}

// All these tests forward to dyn_cast_if_present, so they also provde an
// effective test for its use cases.
TEST(CastingTest, dyn_cast_or_null) {}

TEST(CastingTest, dyn_cast_value_types) {}

TEST(CastingTest, dyn_cast_if_present) {}

TEST(CastingTest, isa_check_predicates) {}

std::unique_ptr<derived> newd() {}
std::unique_ptr<base> newb() {}

TEST(CastingTest, unique_dyn_cast) {}

// These lines are errors...
// foo *F20 = cast<foo>(B2);  // Yields const foo*
// foo &F21 = cast<foo>(B3);  // Yields const foo&
// foo *F22 = cast<foo>(B4);  // Yields const foo*
// foo &F23 = cast_or_null<foo>(B1);
// const foo &F24 = cast_or_null<foo>(B3);

const bar *B2 =;
} // anonymous namespace

bar *llvm::fub() {}

namespace {
namespace inferred_upcasting {
// This test case verifies correct behavior of inferred upcasts when the
// types are statically known to be OK to upcast. This is the case when,
// for example, Derived inherits from Base, and we do `isa<Base>(Derived)`.

// Note: This test will actually fail to compile without inferred
// upcasting.

class Base {};

class Derived : public Base {};

// Even with no explicit classof() in Base, we should still be able to cast
// Derived to its base class.
TEST(CastingTest, UpcastIsInferred) {}

// This test verifies that the inferred upcast takes precedence over an
// explicitly written one. This is important because it verifies that the
// dynamic check gets optimized away.
class UseInferredUpcast {};

TEST(CastingTest, InferredUpcastTakesPrecedence) {}

} // end namespace inferred_upcasting
} // end anonymous namespace

namespace {
namespace pointer_wrappers {

struct Base {};

struct Derived : Base {};

class PTy {};

} // end namespace pointer_wrappers
} // end namespace

namespace llvm {

template <> struct ValueIsPresent<pointer_wrappers::PTy> {};

template <> struct ValueIsPresent<const pointer_wrappers::PTy> {};

template <> struct simplify_type<pointer_wrappers::PTy> {};
template <> struct simplify_type<const pointer_wrappers::PTy> {};

} // end namespace llvm

namespace {
namespace pointer_wrappers {

// Some objects.
pointer_wrappers::Base B;
pointer_wrappers::Derived D;

// Mutable "smart" pointers.
pointer_wrappers::PTy MN(nullptr);
pointer_wrappers::PTy MB(&B);
pointer_wrappers::PTy MD(&D);

// Const "smart" pointers.
const pointer_wrappers::PTy CN(nullptr);
const pointer_wrappers::PTy CB(&B);
const pointer_wrappers::PTy CD(&D);

TEST(CastingTest, smart_isa) {}

TEST(CastingTest, smart_cast) {}

TEST(CastingTest, smart_cast_or_null) {}

TEST(CastingTest, smart_dyn_cast) {}

TEST(CastingTest, smart_dyn_cast_or_null) {}

} // end namespace pointer_wrappers

#ifndef NDEBUG
namespace assertion_checks {
struct Base {
  virtual ~Base() {}
};

struct Derived : public Base {
  static bool classof(const Base *B) { return false; }
};

TEST(CastingTest, assertion_check_const_ref) {
  const Base B;
  EXPECT_DEATH((void)cast<Derived>(B), "argument of incompatible type")
      << "Invalid cast of const ref did not cause an abort()";
}

TEST(CastingTest, assertion_check_ref) {
  Base B;
  EXPECT_DEATH((void)cast<Derived>(B), "argument of incompatible type")
      << "Invalid cast of const ref did not cause an abort()";
}

TEST(CastingTest, assertion_check_ptr) {
  Base B;
  EXPECT_DEATH((void)cast<Derived>(&B), "argument of incompatible type")
      << "Invalid cast of const ref did not cause an abort()";
}

TEST(CastingTest, assertion_check_unique_ptr) {
  auto B = std::make_unique<Base>();
  EXPECT_DEATH((void)cast<Derived>(std::move(B)),
               "argument of incompatible type")
      << "Invalid cast of const ref did not cause an abort()";
}

} // end namespace assertion_checks
#endif
} // end namespace