[libcxx-commits] [libcxx] f893312 - [libcxx] adds concept `std::common_with`

Christopher Di Bella via libcxx-commits libcxx-commits at lists.llvm.org
Wed Mar 3 20:31:27 PST 2021


Author: Christopher Di Bella
Date: 2021-03-03T20:01:11-08:00
New Revision: f893312c1a6a67075f2f38b22e8fd866f0d3d9db

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

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

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

Depends on D96660

Reviewed By: ldionne, #libc

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

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

Modified: 
    libcxx/include/concepts

Removed: 
    


################################################################################
diff  --git a/libcxx/include/concepts b/libcxx/include/concepts
index a64432531936..f13b18fec6f1 100644
--- a/libcxx/include/concepts
+++ b/libcxx/include/concepts
@@ -180,6 +180,23 @@ concept common_reference_with =
   convertible_to<_Tp, common_reference_t<_Tp, _Up>> &&
   convertible_to<_Up, common_reference_t<_Tp, _Up>>;
 
+// [concept.common]
+template<class _Tp, class _Up>
+concept common_with =
+  same_as<common_type_t<_Tp, _Up>, common_type_t<_Up, _Tp>> &&
+  requires {
+    static_cast<common_type_t<_Tp, _Up>>(_VSTD::declval<_Tp>());
+    static_cast<common_type_t<_Tp, _Up>>(_VSTD::declval<_Up>());
+  } &&
+  common_reference_with<
+    add_lvalue_reference_t<const _Tp>,
+    add_lvalue_reference_t<const _Up>> &&
+  common_reference_with<
+    add_lvalue_reference_t<common_type_t<_Tp, _Up>>,
+    common_reference_t<
+      add_lvalue_reference_t<const _Tp>,
+      add_lvalue_reference_t<const _Up>>>;
+
 // [concepts.arithmetic], arithmetic concepts
 template<class _Tp>
 concept integral = is_integral_v<_Tp>;

diff  --git a/libcxx/test/std/concepts/lang/common.compile.pass.cpp b/libcxx/test/std/concepts/lang/common.compile.pass.cpp
new file mode 100644
index 000000000000..6db6b5758024
--- /dev/null
+++ b/libcxx/test/std/concepts/lang/common.compile.pass.cpp
@@ -0,0 +1,992 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_with;
+
+#include <concepts>
+
+template <class T, class U>
+constexpr bool CheckCommonWith() noexcept {
+  constexpr auto result = std::common_with<T, U>;
+  static_assert(std::common_with<T, U&> == result);
+  static_assert(std::common_with<T, const U&> == result);
+  static_assert(std::common_with<T, volatile U&> == result);
+  static_assert(std::common_with<T, const volatile U&> == result);
+  static_assert(std::common_with<T, U&&> == result);
+  static_assert(std::common_with<T, const U&&> == result);
+  static_assert(std::common_with<T, volatile U&&> == result);
+  static_assert(std::common_with<T, const volatile U&&> == result);
+  static_assert(std::common_with<T&, U&&> == result);
+  static_assert(std::common_with<T&, const U&&> == result);
+  static_assert(std::common_with<T&, volatile U&&> == result);
+  static_assert(std::common_with<T&, const volatile U&&> == result);
+  static_assert(std::common_with<const T&, U&&> == result);
+  static_assert(std::common_with<const T&, const U&&> == result);
+  static_assert(std::common_with<const T&, volatile U&&> == result);
+  static_assert(std::common_with<const T&, const volatile U&&> == result);
+  static_assert(std::common_with<volatile T&, U&&> == result);
+  static_assert(std::common_with<volatile T&, const U&&> == result);
+  static_assert(std::common_with<volatile T&, volatile U&&> == result);
+  static_assert(std::common_with<volatile T&, const volatile U&&> == result);
+  static_assert(std::common_with<const volatile T&, U&&> == result);
+  static_assert(std::common_with<const volatile T&, const U&&> == result);
+  static_assert(std::common_with<const volatile T&, volatile U&&> == result);
+  static_assert(std::common_with<const volatile T&, const volatile U&&> ==
+                result);
+  return result;
+}
+
+template <class T, class U>
+constexpr bool HasValidCommonType() noexcept {
+  return requires { typename std::common_type_t<T, U>; }
+  &&std::same_as<std::common_type_t<T, U>, std::common_type_t<U, T> >;
+}
+
+namespace BuiltinTypes {
+// fundamental types
+static_assert(std::common_with<void, void>);
+static_assert(CheckCommonWith<int, int>());
+static_assert(CheckCommonWith<int, long>());
+static_assert(CheckCommonWith<int, unsigned char>());
+#ifndef _LIBCPP_HAS_NO_INT128
+static_assert(CheckCommonWith<int, __int128_t>());
+#endif
+static_assert(CheckCommonWith<int, double>());
+
+// arrays
+static_assert(CheckCommonWith<int[5], int[5]>());
+
+// pointers
+static_assert(CheckCommonWith<int*, int*>());
+static_assert(CheckCommonWith<int*, const int*>());
+static_assert(CheckCommonWith<int*, volatile int*>());
+static_assert(CheckCommonWith<int*, const volatile int*>());
+static_assert(CheckCommonWith<const int*, const int*>());
+static_assert(CheckCommonWith<const int*, volatile int*>());
+static_assert(CheckCommonWith<const int*, const volatile int*>());
+static_assert(CheckCommonWith<volatile int*, const int*>());
+static_assert(CheckCommonWith<volatile int*, volatile int*>());
+static_assert(CheckCommonWith<volatile int*, const volatile int*>());
+static_assert(CheckCommonWith<const volatile int*, const int*>());
+static_assert(CheckCommonWith<const volatile int*, volatile int*>());
+static_assert(CheckCommonWith<const volatile int*, const volatile int*>());
+
+static_assert(CheckCommonWith<int (*)(), int (*)()>());
+static_assert(CheckCommonWith<int (*)(), int (*)() noexcept>());
+static_assert(CheckCommonWith<int (&)(), int (&)()>());
+static_assert(CheckCommonWith<int (&)(), int (&)() noexcept>());
+static_assert(CheckCommonWith<int (&)(), int (*)()>());
+static_assert(CheckCommonWith<int (&)(), int (*)() noexcept>());
+
+struct S {};
+static_assert(CheckCommonWith<int S::*, int S::*>());
+static_assert(CheckCommonWith<int S::*, const int S::*>());
+static_assert(CheckCommonWith<int (S::*)(), int (S::*)()>());
+static_assert(CheckCommonWith<int (S::*)(), int (S::*)() noexcept>());
+static_assert(CheckCommonWith<int (S::*)() const, int (S::*)() const>());
+static_assert(
+    CheckCommonWith<int (S::*)() const, int (S::*)() const noexcept>());
+static_assert(CheckCommonWith<int (S::*)() volatile, int (S::*)() volatile>());
+static_assert(
+    CheckCommonWith<int (S::*)() volatile, int (S::*)() volatile noexcept>());
+static_assert(CheckCommonWith<int (S::*)() const volatile,
+                              int (S::*)() const volatile>());
+static_assert(CheckCommonWith<int (S::*)() const volatile,
+                              int (S::*)() const volatile noexcept>());
+
+// nonsense
+static_assert(!CheckCommonWith<double, float*>());
+static_assert(!CheckCommonWith<int, int[5]>());
+static_assert(!CheckCommonWith<int*, long*>());
+static_assert(!CheckCommonWith<int*, unsigned int*>());
+static_assert(!CheckCommonWith<int (*)(), int (*)(int)>());
+static_assert(!CheckCommonWith<int S::*, float S::*>());
+static_assert(!CheckCommonWith<int (S::*)(), int (S::*)() const>());
+static_assert(!CheckCommonWith<int (S::*)(), int (S::*)() volatile>());
+static_assert(!CheckCommonWith<int (S::*)(), int (S::*)() const volatile>());
+static_assert(!CheckCommonWith<int (S::*)() const, int (S::*)() volatile>());
+static_assert(
+    !CheckCommonWith<int (S::*)() const, int (S::*)() const volatile>());
+static_assert(
+    !CheckCommonWith<int (S::*)() volatile, int (S::*)() const volatile>());
+} // namespace BuiltinTypes
+
+namespace NoDefaultCommonType {
+class T {};
+
+static_assert(!CheckCommonWith<T, int>());
+static_assert(!CheckCommonWith<int, T>());
+static_assert(!CheckCommonWith<T, int[10]>());
+static_assert(!CheckCommonWith<T[10], int>());
+static_assert(!CheckCommonWith<T*, int*>());
+static_assert(!CheckCommonWith<T*, const int*>());
+static_assert(!CheckCommonWith<T*, volatile int*>());
+static_assert(!CheckCommonWith<T*, const volatile int*>());
+static_assert(!CheckCommonWith<const T*, int*>());
+static_assert(!CheckCommonWith<volatile T*, int*>());
+static_assert(!CheckCommonWith<const volatile T*, int*>());
+static_assert(!CheckCommonWith<const T*, const int*>());
+static_assert(!CheckCommonWith<const T*, volatile int*>());
+static_assert(!CheckCommonWith<const T*, const volatile int*>());
+static_assert(!CheckCommonWith<const T*, const int*>());
+static_assert(!CheckCommonWith<volatile T*, const int*>());
+static_assert(!CheckCommonWith<const volatile T*, const int*>());
+static_assert(!CheckCommonWith<volatile T*, const int*>());
+static_assert(!CheckCommonWith<volatile T*, volatile int*>());
+static_assert(!CheckCommonWith<volatile T*, const volatile int*>());
+static_assert(!CheckCommonWith<const T*, volatile int*>());
+static_assert(!CheckCommonWith<volatile T*, volatile int*>());
+static_assert(!CheckCommonWith<const volatile T*, volatile int*>());
+static_assert(!CheckCommonWith<const volatile T*, const int*>());
+static_assert(!CheckCommonWith<const volatile T*, volatile int*>());
+static_assert(!CheckCommonWith<const volatile T*, const volatile int*>());
+static_assert(!CheckCommonWith<const T*, const volatile int*>());
+static_assert(!CheckCommonWith<volatile T*, const volatile int*>());
+static_assert(!CheckCommonWith<const volatile T*, const volatile int*>());
+static_assert(!CheckCommonWith<T&, int&>());
+static_assert(!CheckCommonWith<T&, const int&>());
+static_assert(!CheckCommonWith<T&, volatile int&>());
+static_assert(!CheckCommonWith<T&, const volatile int&>());
+static_assert(!CheckCommonWith<const T&, int&>());
+static_assert(!CheckCommonWith<volatile T&, int&>());
+static_assert(!CheckCommonWith<const volatile T&, int&>());
+static_assert(!CheckCommonWith<const T&, const int&>());
+static_assert(!CheckCommonWith<const T&, volatile int&>());
+static_assert(!CheckCommonWith<const T&, const volatile int&>());
+static_assert(!CheckCommonWith<const T&, const int&>());
+static_assert(!CheckCommonWith<volatile T&, const int&>());
+static_assert(!CheckCommonWith<const volatile T&, const int&>());
+static_assert(!CheckCommonWith<volatile T&, const int&>());
+static_assert(!CheckCommonWith<volatile T&, volatile int&>());
+static_assert(!CheckCommonWith<volatile T&, const volatile int&>());
+static_assert(!CheckCommonWith<const T&, volatile int&>());
+static_assert(!CheckCommonWith<volatile T&, volatile int&>());
+static_assert(!CheckCommonWith<const volatile T&, volatile int&>());
+static_assert(!CheckCommonWith<const volatile T&, const int&>());
+static_assert(!CheckCommonWith<const volatile T&, volatile int&>());
+static_assert(!CheckCommonWith<const volatile T&, const volatile int&>());
+static_assert(!CheckCommonWith<const T&, const volatile int&>());
+static_assert(!CheckCommonWith<volatile T&, const volatile int&>());
+static_assert(!CheckCommonWith<const volatile T&, const volatile int&>());
+static_assert(!CheckCommonWith<T&, int&&>());
+static_assert(!CheckCommonWith<T&, const int&&>());
+static_assert(!CheckCommonWith<T&, volatile int&&>());
+static_assert(!CheckCommonWith<T&, const volatile int&&>());
+static_assert(!CheckCommonWith<const T&, int&&>());
+static_assert(!CheckCommonWith<volatile T&, int&&>());
+static_assert(!CheckCommonWith<const volatile T&, int&&>());
+static_assert(!CheckCommonWith<const T&, const int&&>());
+static_assert(!CheckCommonWith<const T&, volatile int&&>());
+static_assert(!CheckCommonWith<const T&, const volatile int&&>());
+static_assert(!CheckCommonWith<const T&, const int&&>());
+static_assert(!CheckCommonWith<volatile T&, const int&&>());
+static_assert(!CheckCommonWith<const volatile T&, const int&&>());
+static_assert(!CheckCommonWith<volatile T&, const int&&>());
+static_assert(!CheckCommonWith<volatile T&, volatile int&&>());
+static_assert(!CheckCommonWith<volatile T&, const volatile int&&>());
+static_assert(!CheckCommonWith<const T&, volatile int&&>());
+static_assert(!CheckCommonWith<volatile T&, volatile int&&>());
+static_assert(!CheckCommonWith<const volatile T&, volatile int&&>());
+static_assert(!CheckCommonWith<const volatile T&, const int&&>());
+static_assert(!CheckCommonWith<const volatile T&, volatile int&&>());
+static_assert(!CheckCommonWith<const volatile T&, const volatile int&&>());
+static_assert(!CheckCommonWith<const T&, const volatile int&&>());
+static_assert(!CheckCommonWith<volatile T&, const volatile int&&>());
+static_assert(!CheckCommonWith<const volatile T&, const volatile int&&>());
+static_assert(!CheckCommonWith<T&&, int&>());
+static_assert(!CheckCommonWith<T&&, const int&>());
+static_assert(!CheckCommonWith<T&&, volatile int&>());
+static_assert(!CheckCommonWith<T&&, const volatile int&>());
+static_assert(!CheckCommonWith<const T&&, int&>());
+static_assert(!CheckCommonWith<volatile T&&, int&>());
+static_assert(!CheckCommonWith<const volatile T&&, int&>());
+static_assert(!CheckCommonWith<const T&&, const int&>());
+static_assert(!CheckCommonWith<const T&&, volatile int&>());
+static_assert(!CheckCommonWith<const T&&, const volatile int&>());
+static_assert(!CheckCommonWith<const T&&, const int&>());
+static_assert(!CheckCommonWith<volatile T&&, const int&>());
+static_assert(!CheckCommonWith<const volatile T&&, const int&>());
+static_assert(!CheckCommonWith<volatile T&&, const int&>());
+static_assert(!CheckCommonWith<volatile T&&, volatile int&>());
+static_assert(!CheckCommonWith<volatile T&&, const volatile int&>());
+static_assert(!CheckCommonWith<const T&&, volatile int&>());
+static_assert(!CheckCommonWith<volatile T&&, volatile int&>());
+static_assert(!CheckCommonWith<const volatile T&&, volatile int&>());
+static_assert(!CheckCommonWith<const volatile T&&, const int&>());
+static_assert(!CheckCommonWith<const volatile T&&, volatile int&>());
+static_assert(!CheckCommonWith<const volatile T&&, const volatile int&>());
+static_assert(!CheckCommonWith<const T&&, const volatile int&>());
+static_assert(!CheckCommonWith<volatile T&&, const volatile int&>());
+static_assert(!CheckCommonWith<const volatile T&&, const volatile int&>());
+static_assert(!CheckCommonWith<T&&, int&&>());
+static_assert(!CheckCommonWith<T&&, const int&&>());
+static_assert(!CheckCommonWith<T&&, volatile int&&>());
+static_assert(!CheckCommonWith<T&&, const volatile int&&>());
+static_assert(!CheckCommonWith<const T&&, int&&>());
+static_assert(!CheckCommonWith<volatile T&&, int&&>());
+static_assert(!CheckCommonWith<const volatile T&&, int&&>());
+static_assert(!CheckCommonWith<const T&&, const int&&>());
+static_assert(!CheckCommonWith<const T&&, volatile int&&>());
+static_assert(!CheckCommonWith<const T&&, const volatile int&&>());
+static_assert(!CheckCommonWith<const T&&, const int&&>());
+static_assert(!CheckCommonWith<volatile T&&, const int&&>());
+static_assert(!CheckCommonWith<const volatile T&&, const int&&>());
+static_assert(!CheckCommonWith<volatile T&&, const int&&>());
+static_assert(!CheckCommonWith<volatile T&&, volatile int&&>());
+static_assert(!CheckCommonWith<volatile T&&, const volatile int&&>());
+static_assert(!CheckCommonWith<const T&&, volatile int&&>());
+static_assert(!CheckCommonWith<volatile T&&, volatile int&&>());
+static_assert(!CheckCommonWith<const volatile T&&, volatile int&&>());
+static_assert(!CheckCommonWith<const volatile T&&, const int&&>());
+static_assert(!CheckCommonWith<const volatile T&&, volatile int&&>());
+static_assert(!CheckCommonWith<const volatile T&&, const volatile int&&>());
+static_assert(!CheckCommonWith<const T&&, const volatile int&&>());
+static_assert(!CheckCommonWith<volatile T&&, const volatile int&&>());
+static_assert(!CheckCommonWith<const volatile T&&, const volatile int&&>());
+} // namespace NoDefaultCommonType
+
+struct BadBasicCommonType {
+  // 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.
+};
+
+namespace std {
+template <>
+struct common_type<BadBasicCommonType, int> {
+  using type = BadBasicCommonType;
+};
+
+template <>
+struct common_type<int, BadBasicCommonType> {
+  using type = int;
+};
+} // namespace std
+static_assert(requires {
+  typename std::common_type_t<BadBasicCommonType, int>;
+});
+static_assert(requires {
+  typename std::common_type_t<int, BadBasicCommonType>;
+});
+static_assert(!std::same_as<std::common_type_t<BadBasicCommonType, int>,
+                            std::common_type_t<int, BadBasicCommonType> >);
+static_assert(!CheckCommonWith<BadBasicCommonType, int>());
+
+struct DullCommonType {};
+static_assert(!std::convertible_to<DullCommonType, int>);
+
+struct T1 {};
+static_assert(!std::convertible_to<DullCommonType, T1>);
+
+namespace std {
+template <>
+struct common_type<T1, int> {
+  using type = DullCommonType;
+};
+
+template <>
+struct common_type<int, T1> {
+  using type = DullCommonType;
+};
+} // namespace std
+static_assert(HasValidCommonType<T1, int>());
+static_assert(!CheckCommonWith<T1, int>());
+
+struct CommonTypeImplicitlyConstructibleFromInt {
+  explicit(false) CommonTypeImplicitlyConstructibleFromInt(int);
+};
+static_assert(requires {
+  static_cast<CommonTypeImplicitlyConstructibleFromInt>(0);
+});
+
+struct T2 {};
+static_assert(
+    !std::convertible_to<CommonTypeImplicitlyConstructibleFromInt, T2>);
+
+namespace std {
+template <>
+struct common_type<T2, int> {
+  using type = CommonTypeImplicitlyConstructibleFromInt;
+};
+
+template <>
+struct common_type<int, T2> {
+  using type = CommonTypeImplicitlyConstructibleFromInt;
+};
+} // namespace std
+static_assert(HasValidCommonType<T2, int>());
+static_assert(!CheckCommonWith<T2, int>());
+
+struct CommonTypeExplicitlyConstructibleFromInt {
+  explicit CommonTypeExplicitlyConstructibleFromInt(int);
+};
+static_assert(requires {
+  static_cast<CommonTypeExplicitlyConstructibleFromInt>(0);
+});
+
+struct T3 {};
+static_assert(
+    !std::convertible_to<CommonTypeExplicitlyConstructibleFromInt, T2>);
+
+namespace std {
+template <>
+struct common_type<T3, int> {
+  using type = CommonTypeExplicitlyConstructibleFromInt;
+};
+
+template <>
+struct common_type<int, T3> {
+  using type = CommonTypeExplicitlyConstructibleFromInt;
+};
+} // namespace std
+static_assert(HasValidCommonType<T3, int>());
+static_assert(!CheckCommonWith<T3, int>());
+
+struct T4 {};
+struct CommonTypeImplicitlyConstructibleFromT4 {
+  explicit(false) CommonTypeImplicitlyConstructibleFromT4(T4);
+};
+static_assert(requires(T4 t4) {
+  static_cast<CommonTypeImplicitlyConstructibleFromT4>(t4);
+});
+
+namespace std {
+template <>
+struct common_type<T4, int> {
+  using type = CommonTypeImplicitlyConstructibleFromT4;
+};
+
+template <>
+struct common_type<int, T4> {
+  using type = CommonTypeImplicitlyConstructibleFromT4;
+};
+} // namespace std
+static_assert(HasValidCommonType<T4, int>());
+static_assert(!CheckCommonWith<T4, int>());
+
+struct T5 {};
+struct CommonTypeExplicitlyConstructibleFromT5 {
+  explicit CommonTypeExplicitlyConstructibleFromT5(T5);
+};
+static_assert(requires(T5 t5) {
+  static_cast<CommonTypeExplicitlyConstructibleFromT5>(t5);
+});
+
+namespace std {
+template <>
+struct common_type<T5, int> {
+  using type = CommonTypeExplicitlyConstructibleFromT5;
+};
+
+template <>
+struct common_type<int, T5> {
+  using type = CommonTypeExplicitlyConstructibleFromT5;
+};
+} // namespace std
+static_assert(HasValidCommonType<T5, int>());
+static_assert(!CheckCommonWith<T5, int>());
+
+struct T6 {};
+struct CommonTypeNoCommonReference {
+  CommonTypeNoCommonReference(T6);
+  CommonTypeNoCommonReference(int);
+};
+
+namespace std {
+template <>
+struct common_type<T6, int> {
+  using type = CommonTypeNoCommonReference;
+};
+
+template <>
+struct common_type<int, T6> {
+  using type = CommonTypeNoCommonReference;
+};
+
+template <>
+struct common_type<T6&, int&> {};
+
+template <>
+struct common_type<int&, T6&> {};
+
+template <>
+struct common_type<T6&, const int&> {};
+
+template <>
+struct common_type<int&, const T6&> {};
+
+template <>
+struct common_type<T6&, volatile int&> {};
+
+template <>
+struct common_type<int&, volatile T6&> {};
+
+template <>
+struct common_type<T6&, const volatile int&> {};
+
+template <>
+struct common_type<int&, const volatile T6&> {};
+
+template <>
+struct common_type<const T6&, int&> {};
+
+template <>
+struct common_type<const int&, T6&> {};
+
+template <>
+struct common_type<const T6&, const int&> {};
+
+template <>
+struct common_type<const int&, const T6&> {};
+
+template <>
+struct common_type<const T6&, volatile int&> {};
+
+template <>
+struct common_type<const int&, volatile T6&> {};
+
+template <>
+struct common_type<const T6&, const volatile int&> {};
+
+template <>
+struct common_type<const int&, const volatile T6&> {};
+
+template <>
+struct common_type<volatile T6&, int&> {};
+
+template <>
+struct common_type<volatile int&, T6&> {};
+
+template <>
+struct common_type<volatile T6&, const int&> {};
+
+template <>
+struct common_type<volatile int&, const T6&> {};
+
+template <>
+struct common_type<volatile T6&, volatile int&> {};
+
+template <>
+struct common_type<volatile int&, volatile T6&> {};
+
+template <>
+struct common_type<volatile T6&, const volatile int&> {};
+
+template <>
+struct common_type<volatile int&, const volatile T6&> {};
+
+template <>
+struct common_type<const volatile T6&, int&> {};
+
+template <>
+struct common_type<const volatile int&, T6&> {};
+
+template <>
+struct common_type<const volatile T6&, const int&> {};
+
+template <>
+struct common_type<const volatile int&, const T6&> {};
+
+template <>
+struct common_type<const volatile T6&, volatile int&> {};
+
+template <>
+struct common_type<const volatile int&, volatile T6&> {};
+
+template <>
+struct common_type<const volatile T6&, const volatile int&> {};
+
+template <>
+struct common_type<const volatile int&, const volatile T6&> {};
+} // namespace std
+
+template <typename T, typename U>
+constexpr bool HasCommonReference() noexcept {
+  return requires { typename std::common_reference_t<T, U>; };
+}
+
+static_assert(HasValidCommonType<T6, int>());
+static_assert(!HasCommonReference<const T6&, const int&>());
+static_assert(!CheckCommonWith<T6, int>());
+
+struct T7 {};
+struct CommonTypeNoMetaCommonReference {
+  CommonTypeNoMetaCommonReference(T7);
+  CommonTypeNoMetaCommonReference(int);
+};
+
+namespace std {
+template <>
+struct common_type<T7, int> {
+  using type = CommonTypeNoMetaCommonReference;
+};
+
+template <>
+struct common_type<int, T7> {
+  using type = CommonTypeNoMetaCommonReference;
+};
+
+template <>
+struct common_type<T7&, int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<int&, T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<T7&, const int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<int&, const T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<T7&, volatile int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<int&, volatile T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<T7&, const volatile int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<int&, const volatile T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const T7&, int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const int&, T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const T7&, const int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const int&, const T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const T7&, volatile int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const int&, volatile T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const T7&, const volatile int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const int&, const volatile T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<volatile T7&, int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<volatile int&, T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<volatile T7&, const int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<volatile int&, const T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<volatile T7&, volatile int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<volatile int&, volatile T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<volatile T7&, const volatile int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<volatile int&, const volatile T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const volatile T7&, int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const volatile int&, T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const volatile T7&, const int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const volatile int&, const T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const volatile T7&, volatile int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const volatile int&, volatile T7&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const volatile T7&, const volatile int&> {
+  using type = void;
+};
+
+template <>
+struct common_type<const volatile int&, const volatile T7&> {
+  using type = void;
+};
+} // namespace std
+static_assert(HasValidCommonType<T7, int>());
+static_assert(HasValidCommonType<const T7&, const int&>());
+static_assert(HasCommonReference<const T7&, const int&>());
+static_assert(
+    !HasCommonReference<std::common_type_t<T7, int>&,
+                        std::common_reference_t<const T7&, const int&> >());
+static_assert(!CheckCommonWith<T7, int>());
+
+struct CommonWithInt {
+  operator int() const volatile;
+};
+
+namespace std {
+template <>
+struct common_type<CommonWithInt, int> {
+  using type = int;
+};
+
+template <>
+struct common_type<int, CommonWithInt> : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<CommonWithInt&, int&> : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<int&, CommonWithInt&> : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<CommonWithInt&, const int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<int&, const CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<CommonWithInt&, volatile int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<int&, volatile CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<CommonWithInt&, const volatile int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<int&, const volatile CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const CommonWithInt&, int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const int&, CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const CommonWithInt&, const int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const int&, const CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const CommonWithInt&, volatile int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const int&, volatile CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const CommonWithInt&, const volatile int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const int&, const volatile CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<volatile CommonWithInt&, int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<volatile int&, CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<volatile CommonWithInt&, const int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<volatile int&, const CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<volatile CommonWithInt&, volatile int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<volatile int&, volatile CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<volatile CommonWithInt&, const volatile int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<volatile int&, const volatile CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const volatile CommonWithInt&, int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const volatile int&, CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const volatile CommonWithInt&, const int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const volatile int&, const CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const volatile CommonWithInt&, volatile int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const volatile int&, volatile CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const volatile CommonWithInt&, const volatile int&>
+    : common_type<CommonWithInt, int> {};
+
+template <>
+struct common_type<const volatile int&, const volatile CommonWithInt&>
+    : common_type<CommonWithInt, int> {};
+} // namespace std
+static_assert(CheckCommonWith<CommonWithInt, int>());
+
+struct CommonWithIntButRefLong {
+  operator int() const volatile;
+};
+
+namespace std {
+template <>
+struct common_type<CommonWithIntButRefLong, int> {
+  using type = int;
+};
+
+template <>
+struct common_type<int, CommonWithIntButRefLong>
+    : common_type<CommonWithIntButRefLong, int> {};
+
+template <>
+struct common_type<CommonWithIntButRefLong&, int&> {
+  using type = long;
+};
+
+template <>
+struct common_type<int&, CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<CommonWithIntButRefLong&, const int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<int&, const CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<CommonWithIntButRefLong&, volatile int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<int&, volatile CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<CommonWithIntButRefLong&, const volatile int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<int&, const volatile CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const CommonWithIntButRefLong&, int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const int&, CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const CommonWithIntButRefLong&, const int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const int&, const CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const CommonWithIntButRefLong&, volatile int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const int&, volatile CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const CommonWithIntButRefLong&, const volatile int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const int&, const volatile CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<volatile CommonWithIntButRefLong&, int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<volatile int&, CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<volatile CommonWithIntButRefLong&, const int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<volatile int&, const CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<volatile CommonWithIntButRefLong&, volatile int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<volatile int&, volatile CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<volatile CommonWithIntButRefLong&, const volatile int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<volatile int&, const volatile CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const volatile CommonWithIntButRefLong&, int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const volatile int&, CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const volatile CommonWithIntButRefLong&, const int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const volatile int&, const CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const volatile CommonWithIntButRefLong&, volatile int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const volatile int&, volatile CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const volatile CommonWithIntButRefLong&, const volatile int&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+
+template <>
+struct common_type<const volatile int&, const volatile CommonWithIntButRefLong&>
+    : common_type<CommonWithIntButRefLong&, int&> {};
+} // namespace std
+static_assert(CheckCommonWith<CommonWithIntButRefLong, int>());
+
+int main(int, char**) { return 0; }


        


More information about the libcxx-commits mailing list