[libcxx-commits] [libcxx] fdb11c1 - [libc++] Disallow specializing `common_reference` (#141465)
via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jun 4 05:42:02 PDT 2025
Author: A. Jiang
Date: 2025-06-04T20:41:58+08:00
New Revision: fdb11c1be6683e2cff365e3c50ca2d63717e5ea9
URL: https://github.com/llvm/llvm-project/commit/fdb11c1be6683e2cff365e3c50ca2d63717e5ea9
DIFF: https://github.com/llvm/llvm-project/commit/fdb11c1be6683e2cff365e3c50ca2d63717e5ea9.diff
LOG: [libc++] Disallow specializing `common_reference` (#141465)
`common_reference` isn't an exception for [meta.rqmts]/4, so it's better
to disallow users to specialize it.
`indirectly_readable.compile.pass.cpp` was a bit problematic. It
attempted to opt-out common reference type in some wrong ways. Also, the
standard effectively forbids opting-out common reference type for `T&`
and `T&&`. This patch removes and adjusts some problematic cases.
---------
Co-authored-by: Nikolas Klauser <nikolasklauser at berlin.de>
Added:
Modified:
libcxx/docs/ReleaseNotes/21.rst
libcxx/include/__type_traits/common_reference.h
libcxx/test/libcxx/type_traits/no_specializations.verify.cpp
libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/indirectly_readable.compile.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst
index d0383a705190d..6cbc0baf29487 100644
--- a/libcxx/docs/ReleaseNotes/21.rst
+++ b/libcxx/docs/ReleaseNotes/21.rst
@@ -97,6 +97,8 @@ Potentially breaking changes
- The implementation of ``num_put::do_put`` has been replaced to improve the performance, which can lead to
diff erent
output when printing pointers.
+- User-defined specializations of ``std::common_reference`` are diagnosed now. To customize the common reference type, ``std::basic_common_reference`` should be specialized instead.
+
Announcements About Future Releases
-----------------------------------
diff --git a/libcxx/include/__type_traits/common_reference.h b/libcxx/include/__type_traits/common_reference.h
index c27da5251b9b7..7df55f7fecfd5 100644
--- a/libcxx/include/__type_traits/common_reference.h
+++ b/libcxx/include/__type_traits/common_reference.h
@@ -109,11 +109,18 @@ struct __common_ref {};
// Note C: For the common_reference trait applied to a parameter pack [...]
template <class...>
-struct common_reference;
+struct _LIBCPP_NO_SPECIALIZATIONS common_reference;
template <class... _Types>
using common_reference_t = typename common_reference<_Types...>::type;
+template <class, class, template <class> class, template <class> class>
+struct basic_common_reference {};
+
+_LIBCPP_DIAGNOSTIC_PUSH
+# if __has_warning("-Winvalid-specialization")
+_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-specialization")
+# endif
// bullet 1 - sizeof...(T) == 0
template <>
struct common_reference<> {};
@@ -145,9 +152,6 @@ struct __common_reference_sub_bullet1<_Tp, _Up> {
// sub-bullet 2 - Otherwise, if basic_common_reference<remove_cvref_t<T1>, remove_cvref_t<T2>, XREF(T1), XREF(T2)>::type
// is well-formed, then the member typedef `type` denotes that type.
-template <class, class, template <class> class, template <class> class>
-struct basic_common_reference {};
-
template <class _Tp, class _Up>
using __basic_common_reference_t _LIBCPP_NODEBUG =
typename basic_common_reference<remove_cvref_t<_Tp>,
@@ -180,10 +184,11 @@ struct __common_reference_sub_bullet3 : common_type<_Tp, _Up> {};
template <class _Tp, class _Up, class _Vp, class... _Rest>
requires requires { typename common_reference_t<_Tp, _Up>; }
struct common_reference<_Tp, _Up, _Vp, _Rest...> : common_reference<common_reference_t<_Tp, _Up>, _Vp, _Rest...> {};
+_LIBCPP_DIAGNOSTIC_POP
// bullet 5 - Otherwise, there shall be no member `type`.
template <class...>
-struct common_reference {};
+struct _LIBCPP_NO_SPECIALIZATIONS common_reference {};
#endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/test/libcxx/type_traits/no_specializations.verify.cpp b/libcxx/test/libcxx/type_traits/no_specializations.verify.cpp
index 38560161f162e..897ae89365014 100644
--- a/libcxx/test/libcxx/type_traits/no_specializations.verify.cpp
+++ b/libcxx/test/libcxx/type_traits/no_specializations.verify.cpp
@@ -186,5 +186,12 @@ struct std::enable_if<true, S>; // expected-error {{cannot be specialized}}
# if TEST_STD_VER >= 20
template <>
struct std::integral_constant<S, {}>; // expected-error {{cannot be specialized}}
+
+template <>
+struct std::common_reference<S>; // expected-error {{cannot be specialized}}
+template <>
+struct std::common_reference<S, S>; // expected-error {{cannot be specialized}}
+template <>
+struct std::common_reference<S, S, S>; // expected-error {{cannot be specialized}}
# endif
#endif
diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/indirectly_readable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/indirectly_readable.compile.pass.cpp
index 5fc6ffd37caf1..086e79b799c36 100644
--- a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/indirectly_readable.compile.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/indirectly_readable.compile.pass.cpp
@@ -78,16 +78,10 @@ struct missing_iter_value_t {
};
static_assert(!check_indirectly_readable<missing_iter_value_t>());
-struct unrelated_lvalue_ref_and_rvalue_ref {};
-
-struct iter_ref1 {};
-template <>
-struct std::common_reference<iter_ref1&, iter_ref1&&> {};
-
-template <>
-struct std::common_reference<iter_ref1&&, iter_ref1&> {};
-
-static_assert(!std::common_reference_with<iter_ref1&, iter_ref1&&>);
+struct iter_ref1 {
+ iter_ref1(const iter_ref1&) = delete;
+ iter_ref1(iter_ref1&&) = delete;
+};
struct bad_iter_reference_t {
using value_type = int;
@@ -128,24 +122,9 @@ struct
diff erent_reference_types_with_common_reference {
static_assert(check_indirectly_readable<
diff erent_reference_types_with_common_reference>());
struct iter_ref4 {
- operator iter_rvalue_ref() const;
+ operator iter_rvalue_ref();
};
-template <template <class> class XQual, template <class> class YQual>
-struct std::basic_common_reference<iter_ref4, iter_rvalue_ref, XQual, YQual> {
- using type = iter_rvalue_ref;
-};
-template <template <class> class XQual, template <class> class YQual>
-struct std::basic_common_reference<iter_rvalue_ref, iter_ref4, XQual, YQual> {
- using type = iter_rvalue_ref;
-};
-
-// FIXME: This is UB according to [meta.rqmts], and there is no exception for common_reference.
-template <>
-struct std::common_reference<iter_ref4 const&, iter_rvalue_ref&&> {};
-template <>
-struct std::common_reference<iter_rvalue_ref&&, iter_ref4 const&> {};
-
static_assert(std::common_reference_with<iter_ref4&&, iter_rvalue_ref&&>);
static_assert(!std::common_reference_with<iter_ref4 const&, iter_rvalue_ref&&>);
More information about the libcxx-commits
mailing list