422 lines
16 KiB
C++
422 lines
16 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
|
|
// 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;
|
|
}
|