[libcxx-commits] [libcxx] 3f5438c - [libcxx] adds concept `std::common_reference_with`

Christopher Di Bella via libcxx-commits libcxx-commits at lists.llvm.org
Wed Mar 3 17:54:17 PST 2021


Author: Christopher Di Bella
Date: 2021-03-03T17:52:41-08:00
New Revision: 3f5438c46cc8ddfbd221336153700da0bc527752

URL: https://github.com/llvm/llvm-project/commit/3f5438c46cc8ddfbd221336153700da0bc527752
DIFF: https://github.com/llvm/llvm-project/commit/3f5438c46cc8ddfbd221336153700da0bc527752.diff

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

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

Depends on D96657

Reviewed By: ldionne, Mordante, #libc

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

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

Modified: 
    libcxx/include/concepts

Removed: 
    


################################################################################
diff  --git a/libcxx/include/concepts b/libcxx/include/concepts
index 3d57c401d4ea..a64432531936 100644
--- a/libcxx/include/concepts
+++ b/libcxx/include/concepts
@@ -173,6 +173,13 @@ concept convertible_to =
     static_cast<_To>(__f());
   };
 
+// [concept.commonref]
+template<class _Tp, class _Up>
+concept common_reference_with =
+  same_as<common_reference_t<_Tp, _Up>, common_reference_t<_Up, _Tp>> &&
+  convertible_to<_Tp, common_reference_t<_Tp, _Up>> &&
+  convertible_to<_Up, common_reference_t<_Tp, _Up>>;
+
 // [concepts.arithmetic], arithmetic concepts
 template<class _Tp>
 concept integral = is_integral_v<_Tp>;

diff  --git a/libcxx/test/std/concepts/lang/commonreference.compile.pass.cpp b/libcxx/test/std/concepts/lang/commonreference.compile.pass.cpp
new file mode 100644
index 000000000000..114058e5cf6f
--- /dev/null
+++ b/libcxx/test/std/concepts/lang/commonreference.compile.pass.cpp
@@ -0,0 +1,345 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 common_reference_with;
+
+#include <concepts>
+
+template <class T, class U>
+constexpr bool CheckCommonReferenceWith() noexcept {
+  static_assert(std::common_reference_with<T, U&>);
+  static_assert(std::common_reference_with<T, const U&>);
+  static_assert(std::common_reference_with<T, volatile U&>);
+  static_assert(std::common_reference_with<T, const volatile U&>);
+  static_assert(std::common_reference_with<T, U&&>);
+  static_assert(std::common_reference_with<T, const U&&>);
+  static_assert(std::common_reference_with<T, volatile U&&>);
+  static_assert(std::common_reference_with<T, const volatile U&&>);
+  static_assert(std::common_reference_with<T&, U&&>);
+  static_assert(std::common_reference_with<T&, const U&&>);
+  static_assert(std::common_reference_with<T&, volatile U&&>);
+  static_assert(std::common_reference_with<T&, const volatile U&&>);
+  static_assert(std::common_reference_with<const T&, U&&>);
+  static_assert(std::common_reference_with<const T&, const U&&>);
+  static_assert(std::common_reference_with<const T&, volatile U&&>);
+  static_assert(std::common_reference_with<const T&, const volatile U&&>);
+  static_assert(std::common_reference_with<volatile T&, U&&>);
+  static_assert(std::common_reference_with<volatile T&, const U&&>);
+  static_assert(std::common_reference_with<volatile T&, volatile U&&>);
+  static_assert(std::common_reference_with<volatile T&, const volatile U&&>);
+  static_assert(std::common_reference_with<const volatile T&, U&&>);
+  static_assert(std::common_reference_with<const volatile T&, const U&&>);
+  static_assert(std::common_reference_with<const volatile T&, volatile U&&>);
+  static_assert(
+      std::common_reference_with<const volatile T&, const volatile U&&>);
+
+  return std::common_reference_with<T, U>;
+}
+
+namespace BuiltinTypes {
+// fundamental types
+static_assert(std::common_reference_with<void, void>);
+static_assert(CheckCommonReferenceWith<int, int>());
+static_assert(CheckCommonReferenceWith<int, long>());
+static_assert(CheckCommonReferenceWith<int, unsigned char>());
+#ifndef _LIBCPP_HAS_NO_INT128
+static_assert(CheckCommonReferenceWith<int, __int128_t>());
+#endif
+static_assert(CheckCommonReferenceWith<int, double>());
+
+// arrays
+static_assert(CheckCommonReferenceWith<int[5], int[5]>());
+
+// pointers (common with void*)
+static_assert(CheckCommonReferenceWith<int*, void*>());
+static_assert(CheckCommonReferenceWith<int*, const void*>());
+static_assert(CheckCommonReferenceWith<int*, volatile void*>());
+static_assert(CheckCommonReferenceWith<int*, const volatile void*>());
+static_assert(CheckCommonReferenceWith<const int*, void*>());
+static_assert(CheckCommonReferenceWith<const int*, const void*>());
+static_assert(CheckCommonReferenceWith<const int*, volatile void*>());
+static_assert(CheckCommonReferenceWith<const int*, const volatile void*>());
+static_assert(CheckCommonReferenceWith<volatile int*, void*>());
+static_assert(CheckCommonReferenceWith<volatile int*, const void*>());
+static_assert(CheckCommonReferenceWith<volatile int*, volatile void*>());
+static_assert(CheckCommonReferenceWith<volatile int*, const volatile void*>());
+static_assert(CheckCommonReferenceWith<const volatile int*, void*>());
+static_assert(CheckCommonReferenceWith<const volatile int*, const void*>());
+static_assert(CheckCommonReferenceWith<const volatile int*, volatile void*>());
+static_assert(
+    CheckCommonReferenceWith<const volatile int*, const volatile void*>());
+
+static_assert(CheckCommonReferenceWith<int (*)(), int (*)()>());
+static_assert(CheckCommonReferenceWith<int (*)(), int (*)() noexcept>());
+struct S {};
+static_assert(CheckCommonReferenceWith<int S::*, int S::*>());
+static_assert(CheckCommonReferenceWith<int S::*, const int S::*>());
+static_assert(CheckCommonReferenceWith<int (S::*)(), int (S::*)()>());
+static_assert(CheckCommonReferenceWith<int (S::*)(), int (S::*)() noexcept>());
+static_assert(
+    CheckCommonReferenceWith<int (S::*)() const, int (S::*)() const>());
+static_assert(CheckCommonReferenceWith<int (S::*)() const,
+                                       int (S::*)() const noexcept>());
+static_assert(
+    CheckCommonReferenceWith<int (S::*)() volatile, int (S::*)() volatile>());
+static_assert(CheckCommonReferenceWith<int (S::*)() volatile,
+                                       int (S::*)() volatile noexcept>());
+static_assert(CheckCommonReferenceWith<int (S::*)() const volatile,
+                                       int (S::*)() const volatile>());
+static_assert(CheckCommonReferenceWith<int (S::*)() const volatile,
+                                       int (S::*)() const volatile noexcept>());
+
+// nonsense
+static_assert(!std::common_reference_with<double, float*>);
+static_assert(!std::common_reference_with<int, int[5]>);
+static_assert(!std::common_reference_with<int*, long*>);
+static_assert(!std::common_reference_with<int*, unsigned int*>);
+static_assert(!std::common_reference_with<int (*)(), int (*)(int)>);
+static_assert(!std::common_reference_with<int S::*, float S::*>);
+static_assert(!std::common_reference_with<int (S::*)(), int (S::*)() const>);
+static_assert(!std::common_reference_with<int (S::*)(), int (S::*)() volatile>);
+static_assert(
+    !std::common_reference_with<int (S::*)(), int (S::*)() const volatile>);
+static_assert(
+    !std::common_reference_with<int (S::*)() const, int (S::*)() volatile>);
+static_assert(!std::common_reference_with<int (S::*)() const,
+                                          int (S::*)() const volatile>);
+static_assert(!std::common_reference_with<int (S::*)() volatile,
+                                          int (S::*)() const volatile>);
+} // namespace BuiltinTypes
+
+namespace NoDefaultCommonReference {
+class T {};
+
+static_assert(!std::common_reference_with<T, int>);
+static_assert(!std::common_reference_with<int, T>);
+static_assert(!std::common_reference_with<T, int[10]>);
+static_assert(!std::common_reference_with<T[10], int>);
+static_assert(!std::common_reference_with<T*, int*>);
+static_assert(!std::common_reference_with<T*, const int*>);
+static_assert(!std::common_reference_with<T*, volatile int*>);
+static_assert(!std::common_reference_with<T*, const volatile int*>);
+static_assert(!std::common_reference_with<const T*, int*>);
+static_assert(!std::common_reference_with<volatile T*, int*>);
+static_assert(!std::common_reference_with<const volatile T*, int*>);
+static_assert(!std::common_reference_with<const T*, const int*>);
+static_assert(!std::common_reference_with<const T*, volatile int*>);
+static_assert(!std::common_reference_with<const T*, const volatile int*>);
+static_assert(!std::common_reference_with<const T*, const int*>);
+static_assert(!std::common_reference_with<volatile T*, const int*>);
+static_assert(!std::common_reference_with<const volatile T*, const int*>);
+static_assert(!std::common_reference_with<volatile T*, const int*>);
+static_assert(!std::common_reference_with<volatile T*, volatile int*>);
+static_assert(!std::common_reference_with<volatile T*, const volatile int*>);
+static_assert(!std::common_reference_with<const T*, volatile int*>);
+static_assert(!std::common_reference_with<volatile T*, volatile int*>);
+static_assert(!std::common_reference_with<const volatile T*, volatile int*>);
+static_assert(!std::common_reference_with<const volatile T*, const int*>);
+static_assert(!std::common_reference_with<const volatile T*, volatile int*>);
+static_assert(
+    !std::common_reference_with<const volatile T*, const volatile int*>);
+static_assert(!std::common_reference_with<const T*, const volatile int*>);
+static_assert(!std::common_reference_with<volatile T*, const volatile int*>);
+static_assert(
+    !std::common_reference_with<const volatile T*, const volatile int*>);
+static_assert(!std::common_reference_with<T&, int&>);
+static_assert(!std::common_reference_with<T&, const int&>);
+static_assert(!std::common_reference_with<T&, volatile int&>);
+static_assert(!std::common_reference_with<T&, const volatile int&>);
+static_assert(!std::common_reference_with<const T&, int&>);
+static_assert(!std::common_reference_with<volatile T&, int&>);
+static_assert(!std::common_reference_with<const volatile T&, int&>);
+static_assert(!std::common_reference_with<const T&, const int&>);
+static_assert(!std::common_reference_with<const T&, volatile int&>);
+static_assert(!std::common_reference_with<const T&, const volatile int&>);
+static_assert(!std::common_reference_with<const T&, const int&>);
+static_assert(!std::common_reference_with<volatile T&, const int&>);
+static_assert(!std::common_reference_with<const volatile T&, const int&>);
+static_assert(!std::common_reference_with<volatile T&, const int&>);
+static_assert(!std::common_reference_with<volatile T&, volatile int&>);
+static_assert(!std::common_reference_with<volatile T&, const volatile int&>);
+static_assert(!std::common_reference_with<const T&, volatile int&>);
+static_assert(!std::common_reference_with<volatile T&, volatile int&>);
+static_assert(!std::common_reference_with<const volatile T&, volatile int&>);
+static_assert(!std::common_reference_with<const volatile T&, const int&>);
+static_assert(!std::common_reference_with<const volatile T&, volatile int&>);
+static_assert(
+    !std::common_reference_with<const volatile T&, const volatile int&>);
+static_assert(!std::common_reference_with<const T&, const volatile int&>);
+static_assert(!std::common_reference_with<volatile T&, const volatile int&>);
+static_assert(
+    !std::common_reference_with<const volatile T&, const volatile int&>);
+static_assert(!std::common_reference_with<T&, int&&>);
+static_assert(!std::common_reference_with<T&, const int&&>);
+static_assert(!std::common_reference_with<T&, volatile int&&>);
+static_assert(!std::common_reference_with<T&, const volatile int&&>);
+static_assert(!std::common_reference_with<const T&, int&&>);
+static_assert(!std::common_reference_with<volatile T&, int&&>);
+static_assert(!std::common_reference_with<const volatile T&, int&&>);
+static_assert(!std::common_reference_with<const T&, const int&&>);
+static_assert(!std::common_reference_with<const T&, volatile int&&>);
+static_assert(!std::common_reference_with<const T&, const volatile int&&>);
+static_assert(!std::common_reference_with<const T&, const int&&>);
+static_assert(!std::common_reference_with<volatile T&, const int&&>);
+static_assert(!std::common_reference_with<const volatile T&, const int&&>);
+static_assert(!std::common_reference_with<volatile T&, const int&&>);
+static_assert(!std::common_reference_with<volatile T&, volatile int&&>);
+static_assert(!std::common_reference_with<volatile T&, const volatile int&&>);
+static_assert(!std::common_reference_with<const T&, volatile int&&>);
+static_assert(!std::common_reference_with<volatile T&, volatile int&&>);
+static_assert(!std::common_reference_with<const volatile T&, volatile int&&>);
+static_assert(!std::common_reference_with<const volatile T&, const int&&>);
+static_assert(!std::common_reference_with<const volatile T&, volatile int&&>);
+static_assert(
+    !std::common_reference_with<const volatile T&, const volatile int&&>);
+static_assert(!std::common_reference_with<const T&, const volatile int&&>);
+static_assert(!std::common_reference_with<volatile T&, const volatile int&&>);
+static_assert(
+    !std::common_reference_with<const volatile T&, const volatile int&&>);
+static_assert(!std::common_reference_with<T&&, int&>);
+static_assert(!std::common_reference_with<T&&, const int&>);
+static_assert(!std::common_reference_with<T&&, volatile int&>);
+static_assert(!std::common_reference_with<T&&, const volatile int&>);
+static_assert(!std::common_reference_with<const T&&, int&>);
+static_assert(!std::common_reference_with<volatile T&&, int&>);
+static_assert(!std::common_reference_with<const volatile T&&, int&>);
+static_assert(!std::common_reference_with<const T&&, const int&>);
+static_assert(!std::common_reference_with<const T&&, volatile int&>);
+static_assert(!std::common_reference_with<const T&&, const volatile int&>);
+static_assert(!std::common_reference_with<const T&&, const int&>);
+static_assert(!std::common_reference_with<volatile T&&, const int&>);
+static_assert(!std::common_reference_with<const volatile T&&, const int&>);
+static_assert(!std::common_reference_with<volatile T&&, const int&>);
+static_assert(!std::common_reference_with<volatile T&&, volatile int&>);
+static_assert(!std::common_reference_with<volatile T&&, const volatile int&>);
+static_assert(!std::common_reference_with<const T&&, volatile int&>);
+static_assert(!std::common_reference_with<volatile T&&, volatile int&>);
+static_assert(!std::common_reference_with<const volatile T&&, volatile int&>);
+static_assert(!std::common_reference_with<const volatile T&&, const int&>);
+static_assert(!std::common_reference_with<const volatile T&&, volatile int&>);
+static_assert(
+    !std::common_reference_with<const volatile T&&, const volatile int&>);
+static_assert(!std::common_reference_with<const T&&, const volatile int&>);
+static_assert(!std::common_reference_with<volatile T&&, const volatile int&>);
+static_assert(
+    !std::common_reference_with<const volatile T&&, const volatile int&>);
+static_assert(!std::common_reference_with<T&&, int&&>);
+static_assert(!std::common_reference_with<T&&, const int&&>);
+static_assert(!std::common_reference_with<T&&, volatile int&&>);
+static_assert(!std::common_reference_with<T&&, const volatile int&&>);
+static_assert(!std::common_reference_with<const T&&, int&&>);
+static_assert(!std::common_reference_with<volatile T&&, int&&>);
+static_assert(!std::common_reference_with<const volatile T&&, int&&>);
+static_assert(!std::common_reference_with<const T&&, const int&&>);
+static_assert(!std::common_reference_with<const T&&, volatile int&&>);
+static_assert(!std::common_reference_with<const T&&, const volatile int&&>);
+static_assert(!std::common_reference_with<const T&&, const int&&>);
+static_assert(!std::common_reference_with<volatile T&&, const int&&>);
+static_assert(!std::common_reference_with<const volatile T&&, const int&&>);
+static_assert(!std::common_reference_with<volatile T&&, const int&&>);
+static_assert(!std::common_reference_with<volatile T&&, volatile int&&>);
+static_assert(!std::common_reference_with<volatile T&&, const volatile int&&>);
+static_assert(!std::common_reference_with<const T&&, volatile int&&>);
+static_assert(!std::common_reference_with<volatile T&&, volatile int&&>);
+static_assert(!std::common_reference_with<const volatile T&&, volatile int&&>);
+static_assert(!std::common_reference_with<const volatile T&&, const int&&>);
+static_assert(!std::common_reference_with<const volatile T&&, volatile int&&>);
+static_assert(
+    !std::common_reference_with<const volatile T&&, const volatile int&&>);
+static_assert(!std::common_reference_with<const T&&, const volatile int&&>);
+static_assert(!std::common_reference_with<volatile T&&, const volatile int&&>);
+static_assert(
+    !std::common_reference_with<const volatile T&&, const volatile int&&>);
+} // namespace NoDefaultCommonReference
+
+struct BadBasicCommonReference {
+  // This test is ill-formed, NDR. If it ever blows up in our faces: that's a good thing.
+  // In the meantime, the test should be included. If compiler support is added, then an include guard
+  // should be placed so the test doesn't get deleted.
+  operator int() const;
+  operator int&();
+};
+static_assert(std::convertible_to<BadBasicCommonReference, int>);
+static_assert(std::convertible_to<BadBasicCommonReference, int&>);
+
+namespace std {
+template <template <class> class X, template <class> class Y>
+struct basic_common_reference<BadBasicCommonReference, int, X, Y> {
+  using type = BadBasicCommonReference&;
+};
+
+template <template <class> class X, template <class> class Y>
+struct basic_common_reference<int, BadBasicCommonReference, X, Y> {
+  using type = int&;
+};
+} // namespace std
+static_assert(!std::common_reference_with<BadBasicCommonReference, int>);
+
+struct StructNotConvertibleToCommonReference {
+  explicit(false) StructNotConvertibleToCommonReference(int);
+};
+static_assert(std::convertible_to<int, StructNotConvertibleToCommonReference>);
+
+namespace std {
+template <template <class> class X, template <class> class Y>
+struct basic_common_reference<StructNotConvertibleToCommonReference, int, X,
+                              Y> {
+  using type = int&;
+};
+
+template <template <class> class X, template <class> class Y>
+struct basic_common_reference<int, StructNotConvertibleToCommonReference, X,
+                              Y> {
+  using type = int&;
+};
+} // namespace std
+static_assert(
+    !std::common_reference_with<StructNotConvertibleToCommonReference, int>);
+
+struct IntNotConvertibleToCommonReference {
+  operator int&() const;
+};
+
+namespace std {
+template <template <class> class X, template <class> class Y>
+struct basic_common_reference<IntNotConvertibleToCommonReference, int, X, Y> {
+  using type = int&;
+};
+
+template <template <class> class X, template <class> class Y>
+struct basic_common_reference<int, IntNotConvertibleToCommonReference, X, Y> {
+  using type = int&;
+};
+} // namespace std
+static_assert(
+    !std::common_reference_with<StructNotConvertibleToCommonReference, int>);
+
+struct HasCommonReference {
+  explicit(false) HasCommonReference(int);
+  operator int&() const;
+};
+
+namespace std {
+template <template <class> class X, template <class> class Y>
+struct basic_common_reference<HasCommonReference, int, X, Y> {
+  using type = int&;
+};
+
+template <template <class> class X, template <class> class Y>
+struct basic_common_reference<int, HasCommonReference, X, Y> {
+  using type = int&;
+};
+} // namespace std
+static_assert(!std::common_reference_with<HasCommonReference, int>);
+static_assert(std::common_reference_with<HasCommonReference, int&>);
+
+int main(int, char**) { return 0; }


        


More information about the libcxx-commits mailing list