Skip to content

Commit 5b3ce69

Browse files
[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.
1 parent e6b43bd commit 5b3ce69

File tree

3 files changed

+22
-31
lines changed

3 files changed

+22
-31
lines changed

libcxx/include/__type_traits/common_reference.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,18 @@ struct __common_ref {};
109109
// Note C: For the common_reference trait applied to a parameter pack [...]
110110

111111
template <class...>
112-
struct common_reference;
112+
struct _LIBCPP_NO_SPECIALIZATIONS common_reference;
113113

114114
template <class... _Types>
115115
using common_reference_t = typename common_reference<_Types...>::type;
116116

117+
template <class, class, template <class> class, template <class> class>
118+
struct basic_common_reference {};
119+
120+
_LIBCPP_DIAGNOSTIC_PUSH
121+
# if __has_warning("-Winvalid-specialization")
122+
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-specialization")
123+
# endif
117124
// bullet 1 - sizeof...(T) == 0
118125
template <>
119126
struct common_reference<> {};
@@ -145,9 +152,6 @@ struct __common_reference_sub_bullet1<_Tp, _Up> {
145152

146153
// sub-bullet 2 - Otherwise, if basic_common_reference<remove_cvref_t<T1>, remove_cvref_t<T2>, XREF(T1), XREF(T2)>::type
147154
// is well-formed, then the member typedef `type` denotes that type.
148-
template <class, class, template <class> class, template <class> class>
149-
struct basic_common_reference {};
150-
151155
template <class _Tp, class _Up>
152156
using __basic_common_reference_t _LIBCPP_NODEBUG =
153157
typename basic_common_reference<remove_cvref_t<_Tp>,
@@ -180,10 +184,11 @@ struct __common_reference_sub_bullet3 : common_type<_Tp, _Up> {};
180184
template <class _Tp, class _Up, class _Vp, class... _Rest>
181185
requires requires { typename common_reference_t<_Tp, _Up>; }
182186
struct common_reference<_Tp, _Up, _Vp, _Rest...> : common_reference<common_reference_t<_Tp, _Up>, _Vp, _Rest...> {};
187+
_LIBCPP_DIAGNOSTIC_POP
183188

184189
// bullet 5 - Otherwise, there shall be no member `type`.
185190
template <class...>
186-
struct common_reference {};
191+
struct _LIBCPP_NO_SPECIALIZATIONS common_reference{};
187192

188193
#endif // _LIBCPP_STD_VER >= 20
189194

libcxx/test/libcxx/type_traits/no_specializations.verify.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,5 +186,12 @@ struct std::enable_if<true, S>; // expected-error {{cannot be specialized}}
186186
# if TEST_STD_VER >= 20
187187
template <>
188188
struct std::integral_constant<S, {}>; // expected-error {{cannot be specialized}}
189+
190+
template <>
191+
struct std::common_reference<S>; // expected-error {{cannot be specialized}}
192+
template <>
193+
struct std::common_reference<S, S>; // expected-error {{cannot be specialized}}
194+
template <>
195+
struct std::common_reference<S, S, S>; // expected-error {{cannot be specialized}}
189196
# endif
190197
#endif

libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/indirectly_readable.compile.pass.cpp

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,10 @@ struct missing_iter_value_t {
7878
};
7979
static_assert(!check_indirectly_readable<missing_iter_value_t>());
8080

81-
struct unrelated_lvalue_ref_and_rvalue_ref {};
82-
83-
struct iter_ref1 {};
84-
template <>
85-
struct std::common_reference<iter_ref1&, iter_ref1&&> {};
86-
87-
template <>
88-
struct std::common_reference<iter_ref1&&, iter_ref1&> {};
89-
90-
static_assert(!std::common_reference_with<iter_ref1&, iter_ref1&&>);
81+
struct iter_ref1 {
82+
iter_ref1(const iter_ref1&) = delete;
83+
iter_ref1(iter_ref1&&) = delete;
84+
};
9185

9286
struct bad_iter_reference_t {
9387
using value_type = int;
@@ -128,24 +122,9 @@ struct different_reference_types_with_common_reference {
128122
static_assert(check_indirectly_readable<different_reference_types_with_common_reference>());
129123

130124
struct iter_ref4 {
131-
operator iter_rvalue_ref() const;
125+
operator iter_rvalue_ref();
132126
};
133127

134-
template <template <class> class XQual, template <class> class YQual>
135-
struct std::basic_common_reference<iter_ref4, iter_rvalue_ref, XQual, YQual> {
136-
using type = iter_rvalue_ref;
137-
};
138-
template <template <class> class XQual, template <class> class YQual>
139-
struct std::basic_common_reference<iter_rvalue_ref, iter_ref4, XQual, YQual> {
140-
using type = iter_rvalue_ref;
141-
};
142-
143-
// FIXME: This is UB according to [meta.rqmts], and there is no exception for common_reference.
144-
template <>
145-
struct std::common_reference<iter_ref4 const&, iter_rvalue_ref&&> {};
146-
template <>
147-
struct std::common_reference<iter_rvalue_ref&&, iter_ref4 const&> {};
148-
149128
static_assert(std::common_reference_with<iter_ref4&&, iter_rvalue_ref&&>);
150129
static_assert(!std::common_reference_with<iter_ref4 const&, iter_rvalue_ref&&>);
151130

0 commit comments

Comments
 (0)