[libcxx-commits] [libcxx] 8caf835 - [libcxx] adds concept `std::convertible_to`

Christopher Di Bella via libcxx-commits libcxx-commits at lists.llvm.org
Tue Feb 9 19:29:28 PST 2021


Author: Christopher Di Bella
Date: 2021-02-10T03:27:41Z
New Revision: 8caf835337f7bae9d686afdfc16c4897f2da61d8

URL: https://github.com/llvm/llvm-project/commit/8caf835337f7bae9d686afdfc16c4897f2da61d8
DIFF: https://github.com/llvm/llvm-project/commit/8caf835337f7bae9d686afdfc16c4897f2da61d8.diff

LOG: [libcxx] adds concept `std::convertible_to`

Implements parts of:
    - P0898R3 Standard Library Concepts
    - P1754 Rename concepts to standard_case for C++20, while we still can

Differential Revision: https://reviews.llvm.org/D77961

Added: 
    libcxx/test/std/concepts/lang/convertible.compile.pass.cpp

Modified: 
    libcxx/include/concepts

Removed: 
    


################################################################################
diff  --git a/libcxx/include/concepts b/libcxx/include/concepts
index e245e54d0a36..1a18193e6f8e 100644
--- a/libcxx/include/concepts
+++ b/libcxx/include/concepts
@@ -157,6 +157,14 @@ concept __same_as_impl = _VSTD::_IsSame<_Tp, _Up>::value;
 template<class _Tp, class _Up>
 concept same_as = __same_as_impl<_Tp, _Up> && __same_as_impl<_Up, _Tp>;
 
+// [concept.convertible]
+template<class _From, class _To>
+concept convertible_to =
+  is_convertible_v<_From, _To> &&
+  requires(add_rvalue_reference_t<_From> (&__f)()) {
+    static_cast<_To>(__f());
+  };
+
 // [concept.destructible]
 
 template<class _Tp>
@@ -176,7 +184,6 @@ template<class _Tp>
 concept default_initializable = constructible_from<_Tp> &&
     requires { _Tp{}; } && __default_initializable<_Tp>;
 
-
 #endif //_LIBCPP_STD_VER > 17 && defined(__cpp_concepts) && __cpp_concepts >= 201811L
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/test/std/concepts/lang/convertible.compile.pass.cpp b/libcxx/test/std/concepts/lang/convertible.compile.pass.cpp
new file mode 100644
index 000000000000..279df1c3a0b5
--- /dev/null
+++ b/libcxx/test/std/concepts/lang/convertible.compile.pass.cpp
@@ -0,0 +1,422 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++98, 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;
+}


        


More information about the libcxx-commits mailing list