blob: c1818deee9f9689a8654d12ff318e201acd66006 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// template<class From, class To>
// concept convertible_to;
#include <concepts>
#include <type_traits>
namespace {
enum ClassicEnum { a, b };
enum class ScopedEnum { x, y };
struct Empty {};
using nullptr_t = decltype(nullptr);
template <class T, class U>
void CheckConvertibleTo() {
static_assert(std::convertible_to<T, U>);
static_assert(std::convertible_to<const T, U>);
static_assert(std::convertible_to<T, const U>);
static_assert(std::convertible_to<const T, const U>);
}
template <class T, class U>
void CheckNotConvertibleTo() {
static_assert(!std::convertible_to<T, U>);
static_assert(!std::convertible_to<const T, U>);
static_assert(!std::convertible_to<T, const U>);
static_assert(!std::convertible_to<const T, const U>);
}
template <class T, class U>
void CheckIsConvertibleButNotConvertibleTo() {
// Sanity check T is either implicitly xor explicitly convertible to U.
static_assert(std::is_convertible_v<T, U>);
static_assert(std::is_convertible_v<const T, U>);
static_assert(std::is_convertible_v<T, const U>);
static_assert(std::is_convertible_v<const T, const U>);
CheckNotConvertibleTo<T, U>();
}
// Tests that should objectively return false (except for bool and nullptr_t)
template <class T>
constexpr void CommonlyNotConvertibleTo() {
CheckNotConvertibleTo<T, void>();
CheckNotConvertibleTo<T, nullptr_t>();
CheckNotConvertibleTo<T, T*>();
CheckNotConvertibleTo<T, T Empty::*>();
CheckNotConvertibleTo<T, T (Empty::*)()>();
CheckNotConvertibleTo<T, T[sizeof(T)]>();
CheckNotConvertibleTo<T, T (*)()>();
CheckNotConvertibleTo<T, T (&)()>();
CheckNotConvertibleTo<T, T(&&)()>();
}
template <std::same_as<bool> >
constexpr void CommonlyNotConvertibleTo() {
CheckNotConvertibleTo<bool, void>();
CheckNotConvertibleTo<bool, nullptr_t>();
CheckConvertibleTo<bool Empty::*, bool>();
CheckConvertibleTo<bool (Empty::*)(), bool>();
CheckConvertibleTo<bool[2], bool>();
CheckConvertibleTo<bool (*)(), bool>();
CheckConvertibleTo<bool (&)(), bool>();
CheckConvertibleTo<bool(&&)(), bool>();
}
template <std::same_as<nullptr_t> >
constexpr void CommonlyNotConvertibleTo() {
CheckNotConvertibleTo<nullptr_t, void>();
CheckConvertibleTo<nullptr_t, nullptr_t>();
CheckConvertibleTo<nullptr_t, void*>();
CheckConvertibleTo<nullptr_t, int Empty::*>();
CheckConvertibleTo<nullptr_t, void (Empty::*)()>();
CheckNotConvertibleTo<nullptr_t, int[2]>();
CheckConvertibleTo<nullptr_t, void (*)()>();
CheckNotConvertibleTo<nullptr_t, void (&)()>();
CheckNotConvertibleTo<nullptr_t, void(&&)()>();
}
} // namespace
using Function = void();
using NoexceptFunction = void() noexcept;
using ConstFunction = void() const;
using Array = char[1];
struct StringType {
StringType(const char*) {}
};
class NonCopyable {
NonCopyable(NonCopyable&);
};
template <typename T>
class CannotInstantiate {
enum { X = T::ThisExpressionWillBlowUp };
};
struct abstract {
virtual int f() = 0;
};
struct ExplicitlyConvertible;
struct ImplicitlyConvertible;
struct ExplicitlyConstructible {
explicit ExplicitlyConstructible(int);
explicit ExplicitlyConstructible(ExplicitlyConvertible);
explicit ExplicitlyConstructible(ImplicitlyConvertible) = delete;
};
struct ExplicitlyConvertible {
explicit operator ExplicitlyConstructible() const {
return ExplicitlyConstructible(0);
}
};
struct ImplicitlyConstructible;
struct ImplicitlyConvertible {
operator ExplicitlyConstructible() const;
operator ImplicitlyConstructible() const = delete;
};
struct ImplicitlyConstructible {
ImplicitlyConstructible(ImplicitlyConvertible);
};
int main(int, char**) {
// void
CheckConvertibleTo<void, void>();
CheckNotConvertibleTo<void, Function>();
CheckNotConvertibleTo<void, Function&>();
CheckNotConvertibleTo<void, Function*>();
CheckNotConvertibleTo<void, NoexceptFunction>();
CheckNotConvertibleTo<void, NoexceptFunction&>();
CheckNotConvertibleTo<void, NoexceptFunction*>();
CheckNotConvertibleTo<void, Array>();
CheckNotConvertibleTo<void, Array&>();
CheckNotConvertibleTo<void, char>();
CheckNotConvertibleTo<void, char&>();
CheckNotConvertibleTo<void, char*>();
CheckNotConvertibleTo<char, void>();
// Function
CheckNotConvertibleTo<Function, void>();
CheckNotConvertibleTo<Function, Function>();
CheckNotConvertibleTo<Function, NoexceptFunction>();
CheckNotConvertibleTo<Function, NoexceptFunction&>();
CheckNotConvertibleTo<Function, NoexceptFunction*>();
CheckNotConvertibleTo<Function, NoexceptFunction* const>();
CheckConvertibleTo<Function, Function&>();
CheckConvertibleTo<Function, Function*>();
CheckConvertibleTo<Function, Function* const>();
static_assert(std::convertible_to<Function, Function&&>);
static_assert(!std::convertible_to<Function, NoexceptFunction&&>);
CheckNotConvertibleTo<Function, Array>();
CheckNotConvertibleTo<Function, Array&>();
CheckNotConvertibleTo<Function, char>();
CheckNotConvertibleTo<Function, char&>();
CheckNotConvertibleTo<Function, char*>();
// Function&
CheckNotConvertibleTo<Function&, void>();
CheckNotConvertibleTo<Function&, Function>();
CheckConvertibleTo<Function&, Function&>();
CheckConvertibleTo<Function&, Function*>();
CheckNotConvertibleTo<Function&, Array>();
CheckNotConvertibleTo<Function&, Array&>();
CheckNotConvertibleTo<Function&, char>();
CheckNotConvertibleTo<Function&, char&>();
CheckNotConvertibleTo<Function&, char*>();
// Function*
CheckNotConvertibleTo<Function*, void>();
CheckNotConvertibleTo<Function*, Function>();
CheckNotConvertibleTo<Function*, Function&>();
CheckConvertibleTo<Function*, Function*>();
CheckNotConvertibleTo<Function*, Array>();
CheckNotConvertibleTo<Function*, Array&>();
CheckNotConvertibleTo<Function*, char>();
CheckNotConvertibleTo<Function*, char&>();
CheckNotConvertibleTo<Function*, char*>();
// Non-referencable function type
static_assert(!std::convertible_to<ConstFunction, Function>);
static_assert(!std::convertible_to<ConstFunction, Function*>);
static_assert(!std::convertible_to<ConstFunction, Function&>);
static_assert(!std::convertible_to<ConstFunction, Function&&>);
static_assert(!std::convertible_to<Function*, ConstFunction>);
static_assert(!std::convertible_to<Function&, ConstFunction>);
static_assert(!std::convertible_to<ConstFunction, ConstFunction>);
static_assert(!std::convertible_to<ConstFunction, void>);
// NoexceptFunction
CheckNotConvertibleTo<NoexceptFunction, void>();
CheckNotConvertibleTo<NoexceptFunction, Function>();
CheckNotConvertibleTo<NoexceptFunction, NoexceptFunction>();
CheckConvertibleTo<NoexceptFunction, NoexceptFunction&>();
CheckConvertibleTo<NoexceptFunction, NoexceptFunction*>();
CheckConvertibleTo<NoexceptFunction, NoexceptFunction* const>();
CheckConvertibleTo<NoexceptFunction, Function&>();
CheckConvertibleTo<NoexceptFunction, Function*>();
CheckConvertibleTo<NoexceptFunction, Function* const>();
static_assert(std::convertible_to<NoexceptFunction, Function&&>);
static_assert(std::convertible_to<NoexceptFunction, NoexceptFunction&&>);
CheckNotConvertibleTo<NoexceptFunction, Array>();
CheckNotConvertibleTo<NoexceptFunction, Array&>();
CheckNotConvertibleTo<NoexceptFunction, char>();
CheckNotConvertibleTo<NoexceptFunction, char&>();
CheckNotConvertibleTo<NoexceptFunction, char*>();
// NoexceptFunction&
CheckNotConvertibleTo<NoexceptFunction&, void>();
CheckNotConvertibleTo<NoexceptFunction&, Function>();
CheckNotConvertibleTo<NoexceptFunction&, NoexceptFunction>();
CheckConvertibleTo<NoexceptFunction&, Function&>();
CheckConvertibleTo<NoexceptFunction&, NoexceptFunction&>();
CheckConvertibleTo<NoexceptFunction&, Function*>();
CheckConvertibleTo<NoexceptFunction&, NoexceptFunction*>();
CheckNotConvertibleTo<NoexceptFunction&, Array>();
CheckNotConvertibleTo<NoexceptFunction&, Array&>();
CheckNotConvertibleTo<NoexceptFunction&, char>();
CheckNotConvertibleTo<NoexceptFunction&, char&>();
CheckNotConvertibleTo<NoexceptFunction&, char*>();
// NoexceptFunction*
CheckNotConvertibleTo<NoexceptFunction*, void>();
CheckNotConvertibleTo<NoexceptFunction*, Function>();
CheckNotConvertibleTo<NoexceptFunction*, Function&>();
CheckNotConvertibleTo<NoexceptFunction*, NoexceptFunction>();
CheckNotConvertibleTo<NoexceptFunction*, NoexceptFunction&>();
CheckConvertibleTo<NoexceptFunction*, Function*>();
CheckConvertibleTo<NoexceptFunction*, NoexceptFunction*>();
CheckNotConvertibleTo<NoexceptFunction*, Array>();
CheckNotConvertibleTo<NoexceptFunction*, Array&>();
CheckNotConvertibleTo<NoexceptFunction*, char>();
CheckNotConvertibleTo<NoexceptFunction*, char&>();
CheckNotConvertibleTo<NoexceptFunction*, char*>();
// Array
CheckNotConvertibleTo<Array, void>();
CheckNotConvertibleTo<Array, Function>();
CheckNotConvertibleTo<Array, Function&>();
CheckNotConvertibleTo<Array, Function*>();
CheckNotConvertibleTo<Array, NoexceptFunction>();
CheckNotConvertibleTo<Array, NoexceptFunction&>();
CheckNotConvertibleTo<Array, NoexceptFunction*>();
CheckNotConvertibleTo<Array, Array>();
static_assert(!std::convertible_to<Array, Array&>);
static_assert(std::convertible_to<Array, const Array&>);
static_assert(!std::convertible_to<Array, const volatile Array&>);
static_assert(!std::convertible_to<const Array, Array&>);
static_assert(std::convertible_to<const Array, const Array&>);
static_assert(!std::convertible_to<Array, volatile Array&>);
static_assert(!std::convertible_to<Array, const volatile Array&>);
static_assert(std::convertible_to<Array, Array&&>);
static_assert(std::convertible_to<Array, const Array&&>);
static_assert(std::convertible_to<Array, volatile Array&&>);
static_assert(std::convertible_to<Array, const volatile Array&&>);
static_assert(std::convertible_to<const Array, const Array&&>);
static_assert(!std::convertible_to<Array&, Array&&>);
static_assert(!std::convertible_to<Array&&, Array&>);
CheckNotConvertibleTo<Array, char>();
CheckNotConvertibleTo<Array, char&>();
static_assert(std::convertible_to<Array, char*>);
static_assert(std::convertible_to<Array, const char*>);
static_assert(std::convertible_to<Array, char* const>);
static_assert(std::convertible_to<Array, char* const volatile>);
static_assert(!std::convertible_to<const Array, char*>);
static_assert(std::convertible_to<const Array, const char*>);
static_assert(!std::convertible_to<char[42][42], char*>);
static_assert(!std::convertible_to<char[][1], char*>);
// Array&
CheckNotConvertibleTo<Array&, void>();
CheckNotConvertibleTo<Array&, Function>();
CheckNotConvertibleTo<Array&, Function&>();
CheckNotConvertibleTo<Array&, Function*>();
CheckNotConvertibleTo<Array&, NoexceptFunction>();
CheckNotConvertibleTo<Array&, NoexceptFunction&>();
CheckNotConvertibleTo<Array&, NoexceptFunction*>();
CheckNotConvertibleTo<Array&, Array>();
static_assert(std::convertible_to<Array&, Array&>);
static_assert(std::convertible_to<Array&, const Array&>);
static_assert(!std::convertible_to<const Array&, Array&>);
static_assert(std::convertible_to<const Array&, const Array&>);
CheckNotConvertibleTo<Array&, char>();
CheckNotConvertibleTo<Array&, char&>();
static_assert(std::convertible_to<Array&, char*>);
static_assert(std::convertible_to<Array&, const char*>);
static_assert(!std::convertible_to<const Array&, char*>);
static_assert(std::convertible_to<const Array&, const char*>);
static_assert(std::convertible_to<Array, StringType>);
static_assert(std::convertible_to<char(&)[], StringType>);
// char
CheckNotConvertibleTo<char, void>();
CheckNotConvertibleTo<char, Function>();
CheckNotConvertibleTo<char, Function&>();
CheckNotConvertibleTo<char, Function*>();
CheckNotConvertibleTo<char, NoexceptFunction>();
CheckNotConvertibleTo<char, NoexceptFunction&>();
CheckNotConvertibleTo<char, NoexceptFunction*>();
CheckNotConvertibleTo<char, Array>();
CheckNotConvertibleTo<char, Array&>();
CheckConvertibleTo<char, char>();
static_assert(!std::convertible_to<char, char&>);
static_assert(std::convertible_to<char, const char&>);
static_assert(!std::convertible_to<const char, char&>);
static_assert(std::convertible_to<const char, const char&>);
CheckNotConvertibleTo<char, char*>();
// char&
CheckNotConvertibleTo<char&, void>();
CheckNotConvertibleTo<char&, Function>();
CheckNotConvertibleTo<char&, Function&>();
CheckNotConvertibleTo<char&, Function*>();
CheckNotConvertibleTo<char&, NoexceptFunction>();
CheckNotConvertibleTo<char&, NoexceptFunction&>();
CheckNotConvertibleTo<char&, NoexceptFunction*>();
CheckNotConvertibleTo<char&, Array>();
CheckNotConvertibleTo<char&, Array&>();
CheckConvertibleTo<char&, char>();
static_assert(std::convertible_to<char&, char&>);
static_assert(std::convertible_to<char&, const char&>);
static_assert(!std::convertible_to<const char&, char&>);
static_assert(std::convertible_to<const char&, const char&>);
CheckNotConvertibleTo<char&, char*>();
// char*
CheckNotConvertibleTo<char*, void>();
CheckNotConvertibleTo<char*, Function>();
CheckNotConvertibleTo<char*, Function&>();
CheckNotConvertibleTo<char*, Function*>();
CheckNotConvertibleTo<char*, NoexceptFunction>();
CheckNotConvertibleTo<char*, NoexceptFunction&>();
CheckNotConvertibleTo<char*, NoexceptFunction*>();
CheckNotConvertibleTo<char*, Array>();
CheckNotConvertibleTo<char*, Array&>();
CheckNotConvertibleTo<char*, char>();
CheckNotConvertibleTo<char*, char&>();
static_assert(std::convertible_to<char*, char*>);
static_assert(std::convertible_to<char*, const char*>);
static_assert(!std::convertible_to<const char*, char*>);
static_assert(std::convertible_to<const char*, const char*>);
// NonCopyable
static_assert(std::convertible_to<NonCopyable&, NonCopyable&>);
static_assert(std::convertible_to<NonCopyable&, const NonCopyable&>);
static_assert(std::convertible_to<NonCopyable&, const volatile NonCopyable&>);
static_assert(std::convertible_to<NonCopyable&, volatile NonCopyable&>);
static_assert(std::convertible_to<const NonCopyable&, const NonCopyable&>);
static_assert(
std::convertible_to<const NonCopyable&, const volatile NonCopyable&>);
static_assert(
std::convertible_to<volatile NonCopyable&, const volatile NonCopyable&>);
static_assert(std::convertible_to<const volatile NonCopyable&,
const volatile NonCopyable&>);
static_assert(!std::convertible_to<const NonCopyable&, NonCopyable&>);
// This test requires Access control SFINAE which we only have in C++11 or when
// we are using the compiler builtin for convertible_to.
CheckNotConvertibleTo<NonCopyable&, NonCopyable>();
// Ensure that CannotInstantiate is not instantiated by convertible_to when it is not needed.
// For example CannotInstantiate is instantiated as a part of ADL lookup for arguments of type CannotInstantiate*.
static_assert(
std::convertible_to<CannotInstantiate<int>*, CannotInstantiate<int>*>);
// Test for PR13592
static_assert(!std::convertible_to<abstract, abstract>);
CommonlyNotConvertibleTo<int>();
CommonlyNotConvertibleTo<bool>();
CommonlyNotConvertibleTo<nullptr_t>();
CheckNotConvertibleTo<int, ExplicitlyConstructible>();
CheckNotConvertibleTo<ExplicitlyConvertible, ExplicitlyConstructible>();
CheckNotConvertibleTo<ExplicitlyConstructible, ExplicitlyConvertible>();
CheckIsConvertibleButNotConvertibleTo<ImplicitlyConvertible,
ExplicitlyConstructible>();
CheckNotConvertibleTo<ImplicitlyConstructible, ImplicitlyConvertible>();
return 0;
}