Skip to content

[libc++] Use [[clang::no_specializations]] to diagnose invalid user specializations #118167

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion libcxx/include/__compare/compare_three_way_result.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ struct _LIBCPP_HIDE_FROM_ABI __compare_three_way_result<
};

template <class _Tp, class _Up = _Tp>
struct _LIBCPP_TEMPLATE_VIS compare_three_way_result : __compare_three_way_result<_Tp, _Up, void> {};
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS compare_three_way_result
: __compare_three_way_result<_Tp, _Up, void> {};

template <class _Tp, class _Up = _Tp>
using compare_three_way_result_t = typename compare_three_way_result<_Tp, _Up>::type;
Expand Down
7 changes: 7 additions & 0 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,13 @@ typedef __char32_t char32_t;

# define _LIBCPP_NODEBUG [[__gnu__::__nodebug__]]

# if __has_cpp_attribute(_Clang::__no_specializations__)
# define _LIBCPP_NO_SPECIALIZATIONS \
[[_Clang::__no_specializations__("Users are not allowed to specialize this standard library entity")]]
# else
# define _LIBCPP_NO_SPECIALIZATIONS
# endif

# if __has_attribute(__standalone_debug__)
# define _LIBCPP_STANDALONE_DEBUG __attribute__((__standalone_debug__))
# else
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__format/format_arg.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ class __basic_format_arg_value {
};

template <class _Context>
class _LIBCPP_TEMPLATE_VIS basic_format_arg {
class _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS basic_format_arg {
public:
class _LIBCPP_TEMPLATE_VIS handle;

Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__ranges/range_adaptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ template <_RangeAdaptorClosure _Closure, _RangeAdaptorClosure _OtherClosure>
# if _LIBCPP_STD_VER >= 23
template <class _Tp>
requires is_class_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>>
class range_adaptor_closure : public __range_adaptor_closure<_Tp> {};
class _LIBCPP_NO_SPECIALIZATIONS range_adaptor_closure : public __range_adaptor_closure<_Tp> {};
# endif // _LIBCPP_STD_VER >= 23

} // namespace ranges
Expand Down
6 changes: 3 additions & 3 deletions libcxx/include/__type_traits/add_cv_quals.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS add_const {
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS add_const {
using type _LIBCPP_NODEBUG = const _Tp;
};

Expand All @@ -28,7 +28,7 @@ using add_const_t = typename add_const<_Tp>::type;
#endif

template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS add_cv {
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS add_cv {
using type _LIBCPP_NODEBUG = const volatile _Tp;
};

Expand All @@ -38,7 +38,7 @@ using add_cv_t = typename add_cv<_Tp>::type;
#endif

template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS add_volatile {
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS add_volatile {
using type _LIBCPP_NODEBUG = volatile _Tp;
};

Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__type_traits/add_lvalue_reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ using __add_lvalue_reference_t = typename __add_lvalue_reference_impl<_Tp>::type
#endif // __has_builtin(__add_lvalue_reference)

template <class _Tp>
struct add_lvalue_reference {
struct _LIBCPP_NO_SPECIALIZATIONS add_lvalue_reference {
using type _LIBCPP_NODEBUG = __add_lvalue_reference_t<_Tp>;
};

Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__type_traits/add_pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ using __add_pointer_t = typename __add_pointer_impl<_Tp>::type;
#endif // !defined(_LIBCPP_WORKAROUND_OBJCXX_COMPILER_INTRINSICS) && __has_builtin(__add_pointer)

template <class _Tp>
struct add_pointer {
struct _LIBCPP_NO_SPECIALIZATIONS add_pointer {
using type _LIBCPP_NODEBUG = __add_pointer_t<_Tp>;
};

Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__type_traits/add_rvalue_reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ using __add_rvalue_reference_t = typename __add_rvalue_reference_impl<_Tp>::type
#endif // __has_builtin(__add_rvalue_reference)

template <class _Tp>
struct add_rvalue_reference {
struct _LIBCPP_NO_SPECIALIZATIONS add_rvalue_reference {
using type = __add_rvalue_reference_t<_Tp>;
};

Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__type_traits/aligned_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ struct __find_max_align<__type_list<_Head, _Tail...>, _Len>
__select_align<_Len, _Head::value, __find_max_align<__type_list<_Tail...>, _Len>::value>::value> {};

template <size_t _Len, size_t _Align = __find_max_align<__all_types, _Len>::value>
struct _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_TEMPLATE_VIS aligned_storage {
struct _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS aligned_storage {
union _ALIGNAS(_Align) type {
unsigned char __data[(_Len + _Align - 1) / _Align * _Align];
};
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__type_traits/aligned_union.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct __static_max<_I0, _I1, _In...> {
};

template <size_t _Len, class _Type0, class... _Types>
struct _LIBCPP_DEPRECATED_IN_CXX23 aligned_union {
struct _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_NO_SPECIALIZATIONS aligned_union {
static const size_t alignment_value =
__static_max<_LIBCPP_PREFERRED_ALIGNOF(_Type0), _LIBCPP_PREFERRED_ALIGNOF(_Types)...>::value;
static const size_t __len = __static_max<_Len, sizeof(_Type0), sizeof(_Types)...>::value;
Expand Down
5 changes: 3 additions & 2 deletions libcxx/include/__type_traits/alignment_of.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@
_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS alignment_of : public integral_constant<size_t, _LIBCPP_ALIGNOF(_Tp)> {};
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS alignment_of
: public integral_constant<size_t, _LIBCPP_ALIGNOF(_Tp)> {};

#if _LIBCPP_STD_VER >= 17
template <class _Tp>
inline constexpr size_t alignment_of_v = _LIBCPP_ALIGNOF(_Tp);
_LIBCPP_NO_SPECIALIZATIONS inline constexpr size_t alignment_of_v = _LIBCPP_ALIGNOF(_Tp);
#endif

_LIBCPP_END_NAMESPACE_STD
Expand Down
8 changes: 7 additions & 1 deletion libcxx/include/__type_traits/conditional.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,19 @@ template <bool _Cond, class _IfRes, class _ElseRes>
using _If _LIBCPP_NODEBUG = typename _IfImpl<_Cond>::template _Select<_IfRes, _ElseRes>;

template <bool _Bp, class _If, class _Then>
struct _LIBCPP_TEMPLATE_VIS conditional {
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS conditional {
using type _LIBCPP_NODEBUG = _If;
};

_LIBCPP_DIAGNOSTIC_PUSH
#if __has_warning("-Winvalid-specialization")
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-specialization")
#endif
template <class _If, class _Then>
struct _LIBCPP_TEMPLATE_VIS conditional<false, _If, _Then> {
using type _LIBCPP_NODEBUG = _Then;
};
_LIBCPP_DIAGNOSTIC_POP

#if _LIBCPP_STD_VER >= 14
template <bool _Bp, class _IfRes, class _ElseRes>
Expand Down
9 changes: 7 additions & 2 deletions libcxx/include/__type_traits/conjunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,21 @@ struct __all : _IsSame<__all_dummy<_Pred...>, __all_dummy<((void)_Pred, true)...
#if _LIBCPP_STD_VER >= 17

template <class...>
struct conjunction : true_type {};
struct _LIBCPP_NO_SPECIALIZATIONS conjunction : true_type {};

_LIBCPP_DIAGNOSTIC_PUSH
# if __has_warning("-Winvalid-specialization")
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-specialization")
# endif
template <class _Arg>
struct conjunction<_Arg> : _Arg {};

template <class _Arg, class... _Args>
struct conjunction<_Arg, _Args...> : conditional_t<!bool(_Arg::value), _Arg, conjunction<_Args...>> {};
_LIBCPP_DIAGNOSTIC_POP

template <class... _Args>
inline constexpr bool conjunction_v = conjunction<_Args...>::value;
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool conjunction_v = conjunction<_Args...>::value;

#endif // _LIBCPP_STD_VER >= 17

Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__type_traits/decay.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ template <class _Tp>
using __decay_t _LIBCPP_NODEBUG = __decay(_Tp);

template <class _Tp>
struct decay {
struct _LIBCPP_NO_SPECIALIZATIONS decay {
using type _LIBCPP_NODEBUG = __decay_t<_Tp>;
};

Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/__type_traits/disjunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ using _Or _LIBCPP_NODEBUG = typename _OrImpl<sizeof...(_Args) != 0>::template _R
#if _LIBCPP_STD_VER >= 17

template <class... _Args>
struct disjunction : _Or<_Args...> {};
struct _LIBCPP_NO_SPECIALIZATIONS disjunction : _Or<_Args...> {};

template <class... _Args>
inline constexpr bool disjunction_v = _Or<_Args...>::value;
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool disjunction_v = _Or<_Args...>::value;

#endif // _LIBCPP_STD_VER >= 17

Expand Down
8 changes: 7 additions & 1 deletion libcxx/include/__type_traits/enable_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,17 @@
_LIBCPP_BEGIN_NAMESPACE_STD

template <bool, class _Tp = void>
struct _LIBCPP_TEMPLATE_VIS enable_if {};
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS enable_if{};

_LIBCPP_DIAGNOSTIC_PUSH
#if __has_warning("-Winvalid-specialization")
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-specialization")
#endif
template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS enable_if<true, _Tp> {
typedef _Tp type;
};
_LIBCPP_DIAGNOSTIC_POP

template <bool _Bp, class _Tp = void>
using __enable_if_t _LIBCPP_NODEBUG = typename enable_if<_Bp, _Tp>::type;
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/__type_traits/extent.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if __has_builtin(__array_extent)

template <class _Tp, size_t _Dim = 0>
struct _LIBCPP_TEMPLATE_VIS extent : integral_constant<size_t, __array_extent(_Tp, _Dim)> {};
struct _LIBCPP_NO_SPECIALIZATIONS _LIBCPP_TEMPLATE_VIS extent : integral_constant<size_t, __array_extent(_Tp, _Dim)> {};

# if _LIBCPP_STD_VER >= 17
template <class _Tp, unsigned _Ip = 0>
inline constexpr size_t extent_v = __array_extent(_Tp, _Ip);
_LIBCPP_NO_SPECIALIZATIONS inline constexpr size_t extent_v = __array_extent(_Tp, _Ip);
# endif

#else // __has_builtin(__array_extent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 17

template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS has_unique_object_representations
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS has_unique_object_representations
// TODO: We work around a Clang and GCC bug in __has_unique_object_representations by using remove_all_extents
// even though it should not be necessary. This was reported to the compilers:
// - Clang: https://github.com/llvm/llvm-project/issues/95311
Expand All @@ -31,7 +31,8 @@ struct _LIBCPP_TEMPLATE_VIS has_unique_object_representations
: public integral_constant<bool, __has_unique_object_representations(remove_all_extents_t<_Tp>)> {};

template <class _Tp>
inline constexpr bool has_unique_object_representations_v = __has_unique_object_representations(_Tp);
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool has_unique_object_representations_v =
__has_unique_object_representations(_Tp);

#endif

Expand Down
5 changes: 3 additions & 2 deletions libcxx/include/__type_traits/has_virtual_destructor.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS has_virtual_destructor : public integral_constant<bool, __has_virtual_destructor(_Tp)> {};
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS has_virtual_destructor
: public integral_constant<bool, __has_virtual_destructor(_Tp)> {};

#if _LIBCPP_STD_VER >= 17
template <class _Tp>
inline constexpr bool has_virtual_destructor_v = __has_virtual_destructor(_Tp);
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool has_virtual_destructor_v = __has_virtual_destructor(_Tp);
#endif

_LIBCPP_END_NAMESPACE_STD
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__type_traits/integral_constant.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Tp, _Tp __v>
struct _LIBCPP_TEMPLATE_VIS integral_constant {
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS integral_constant {
static inline _LIBCPP_CONSTEXPR const _Tp value = __v;
typedef _Tp value_type;
typedef integral_constant type;
Expand Down
23 changes: 13 additions & 10 deletions libcxx/include/__type_traits/invoke.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,34 +278,37 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Ret __invoke_r(_Args&&... _
// is_invocable

template <class _Fn, class... _Args>
struct _LIBCPP_TEMPLATE_VIS is_invocable : bool_constant<__is_invocable_v<_Fn, _Args...>> {};
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS is_invocable : bool_constant<__is_invocable_v<_Fn, _Args...>> {};

template <class _Ret, class _Fn, class... _Args>
struct _LIBCPP_TEMPLATE_VIS is_invocable_r : bool_constant<__is_invocable_r_v<_Ret, _Fn, _Args...>> {};
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS is_invocable_r
: bool_constant<__is_invocable_r_v<_Ret, _Fn, _Args...>> {};

template <class _Fn, class... _Args>
inline constexpr bool is_invocable_v = __is_invocable_v<_Fn, _Args...>;
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_invocable_v = __is_invocable_v<_Fn, _Args...>;

template <class _Ret, class _Fn, class... _Args>
inline constexpr bool is_invocable_r_v = __is_invocable_r_v<_Ret, _Fn, _Args...>;
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_invocable_r_v = __is_invocable_r_v<_Ret, _Fn, _Args...>;

// is_nothrow_invocable

template <class _Fn, class... _Args>
struct _LIBCPP_TEMPLATE_VIS is_nothrow_invocable : bool_constant<__nothrow_invokable<_Fn, _Args...>::value> {};
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS is_nothrow_invocable
: bool_constant<__nothrow_invokable<_Fn, _Args...>::value> {};

template <class _Ret, class _Fn, class... _Args>
struct _LIBCPP_TEMPLATE_VIS is_nothrow_invocable_r : bool_constant<__nothrow_invokable_r<_Ret, _Fn, _Args...>::value> {
};
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS is_nothrow_invocable_r
: bool_constant<__nothrow_invokable_r<_Ret, _Fn, _Args...>::value> {};

template <class _Fn, class... _Args>
inline constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<_Fn, _Args...>::value;
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<_Fn, _Args...>::value;

template <class _Ret, class _Fn, class... _Args>
inline constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value;
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_nothrow_invocable_r_v =
is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value;

template <class _Fn, class... _Args>
struct _LIBCPP_TEMPLATE_VIS invoke_result : __invoke_result<_Fn, _Args...> {};
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS invoke_result : __invoke_result<_Fn, _Args...> {};

template <class _Fn, class... _Args>
using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
Expand Down
5 changes: 3 additions & 2 deletions libcxx/include/__type_traits/is_abstract.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS is_abstract : public integral_constant<bool, __is_abstract(_Tp)> {};
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS is_abstract
: public integral_constant<bool, __is_abstract(_Tp)> {};

#if _LIBCPP_STD_VER >= 17
template <class _Tp>
inline constexpr bool is_abstract_v = __is_abstract(_Tp);
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_abstract_v = __is_abstract(_Tp);
#endif

_LIBCPP_END_NAMESPACE_STD
Expand Down
5 changes: 3 additions & 2 deletions libcxx/include/__type_traits/is_aggregate.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 17

template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS is_aggregate : public integral_constant<bool, __is_aggregate(_Tp)> {};
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS is_aggregate
: public integral_constant<bool, __is_aggregate(_Tp)> {};

template <class _Tp>
inline constexpr bool is_aggregate_v = __is_aggregate(_Tp);
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_aggregate_v = __is_aggregate(_Tp);

#endif // _LIBCPP_STD_VER >= 17

Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/__type_traits/is_arithmetic.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS is_arithmetic
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS is_arithmetic
: public integral_constant<bool, is_integral<_Tp>::value || is_floating_point<_Tp>::value> {};

#if _LIBCPP_STD_VER >= 17
template <class _Tp>
inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
#endif

_LIBCPP_END_NAMESPACE_STD
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/__type_traits/is_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD
(!defined(_LIBCPP_COMPILER_CLANG_BASED) || (defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 1900))

template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS is_array : _BoolConstant<__is_array(_Tp)> {};
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS is_array : _BoolConstant<__is_array(_Tp)> {};

# if _LIBCPP_STD_VER >= 17
template <class _Tp>
inline constexpr bool is_array_v = __is_array(_Tp);
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_array_v = __is_array(_Tp);
# endif

#else
Expand Down
Loading
Loading