From ea73cc5f1a5da65e9bf98a074b1d0220f177af0e Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 26 May 2025 17:16:33 +0800 Subject: [PATCH 1/4] [libc++] Disallow specializing `common_reference` `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. --- .../include/__type_traits/common_reference.h | 15 ++++++--- .../type_traits/no_specializations.verify.cpp | 7 +++++ .../indirectly_readable.compile.pass.cpp | 31 +++---------------- 3 files changed, 22 insertions(+), 31 deletions(-) diff --git a/libcxx/include/__type_traits/common_reference.h b/libcxx/include/__type_traits/common_reference.h index c27da5251b9b7..a2e360405ecf6 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 -struct common_reference; +struct _LIBCPP_NO_SPECIALIZATIONS common_reference; template using common_reference_t = typename common_reference<_Types...>::type; +template class, template 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, XREF(T1), XREF(T2)>::type // is well-formed, then the member typedef `type` denotes that type. -template class, template class> -struct basic_common_reference {}; - template using __basic_common_reference_t _LIBCPP_NODEBUG = typename basic_common_reference, @@ -180,10 +184,11 @@ struct __common_reference_sub_bullet3 : common_type<_Tp, _Up> {}; template requires requires { typename common_reference_t<_Tp, _Up>; } struct common_reference<_Tp, _Up, _Vp, _Rest...> : common_reference, _Vp, _Rest...> {}; +_LIBCPP_DIAGNOSTIC_POP // bullet 5 - Otherwise, there shall be no member `type`. template -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; // expected-error {{cannot be specialized}} # if TEST_STD_VER >= 20 template <> struct std::integral_constant; // expected-error {{cannot be specialized}} + +template <> +struct std::common_reference; // expected-error {{cannot be specialized}} +template <> +struct std::common_reference; // expected-error {{cannot be specialized}} +template <> +struct std::common_reference; // 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()); -struct unrelated_lvalue_ref_and_rvalue_ref {}; - -struct iter_ref1 {}; -template <> -struct std::common_reference {}; - -template <> -struct std::common_reference {}; - -static_assert(!std::common_reference_with); +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 different_reference_types_with_common_reference { static_assert(check_indirectly_readable()); struct iter_ref4 { - operator iter_rvalue_ref() const; + operator iter_rvalue_ref(); }; -template