template<bool, typename, typename>
struct conditional;
+ template <typename _Type>
+ struct __type_identity {
+ using type = _Type;
+ };
+
template<typename...>
struct __or_;
#endif // C++17
+ // Forward declarations
+ template<typename>
+ struct is_reference;
+ template<typename>
+ struct is_function;
+ template<typename>
+ struct is_void;
+ template<typename>
+ struct __is_array_unknown_bounds;
+
+ // Helper functions that return false_type for incomplete classes,
+ // incomplete unions and arrays of known bound from those.
+
+ template <typename _T, size_t = sizeof(_T)>
+ constexpr true_type __is_complete_or_unbounded(__type_identity<_T>)
+ { return {}; }
+
+ template <typename _TypeIdentity,
+ typename _NestedType = typename _TypeIdentity::type>
+ constexpr typename __or_<
+ is_reference<_NestedType>,
+ is_function<_NestedType>,
+ is_void<_NestedType>,
+ __is_array_unknown_bounds<_NestedType>
+ >::type __is_complete_or_unbounded(_TypeIdentity)
+ { return {}; }
+
// For several sfinae-friendly trait implementations we transport both the
// result information (as the member type) and the failure information (no
// member type). This is very similar to std::enable_if, but we cannot use
struct is_rvalue_reference<_Tp&&>
: public true_type { };
- template<typename>
- struct is_function;
-
template<typename>
struct __is_member_object_pointer_helper
: public false_type { };
template<typename _Tp>
struct is_trivial
: public integral_constant<bool, __is_trivial(_Tp)>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
// is_trivially_copyable
template<typename _Tp>
struct is_trivially_copyable
: public integral_constant<bool, __is_trivially_copyable(_Tp)>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// is_standard_layout
template<typename _Tp>
struct is_standard_layout
: public integral_constant<bool, __is_standard_layout(_Tp)>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// is_pod
// Could use is_standard_layout && is_trivial instead of the builtin.
template<typename _Tp>
struct is_pod
: public integral_constant<bool, __is_pod(_Tp)>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// is_literal_type
template<typename _Tp>
struct is_literal_type
: public integral_constant<bool, __is_literal_type(_Tp)>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// is_empty
template<typename _Tp>
struct is_empty
: public integral_constant<bool, __is_empty(_Tp)>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// is_polymorphic
template<typename _Tp>
struct is_polymorphic
: public integral_constant<bool, __is_polymorphic(_Tp)>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
#if __cplusplus >= 201402L
#define __cpp_lib_is_final 201402L
template<typename _Tp>
struct is_final
: public integral_constant<bool, __is_final(_Tp)>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
#endif
/// is_abstract
template<typename _Tp>
struct is_abstract
: public integral_constant<bool, __is_abstract(_Tp)>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp,
bool = is_arithmetic<_Tp>::value>
template<typename _Tp>
struct is_destructible
: public __is_destructible_safe<_Tp>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
// is_nothrow_destructible requires that is_destructible is
// satisfied as well. We realize that by mimicing the
template<typename _Tp>
struct is_nothrow_destructible
: public __is_nt_destructible_safe<_Tp>::type
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
+
+ template<typename _Tp, typename... _Args>
+ struct __is_constructible_impl
+ : public __bool_constant<__is_constructible(_Tp, _Args...)>
{ };
/// is_constructible
template<typename _Tp, typename... _Args>
struct is_constructible
- : public __bool_constant<__is_constructible(_Tp, _Args...)>
- { };
+ : public __is_constructible_impl<_Tp, _Args...>
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// is_default_constructible
template<typename _Tp>
struct is_default_constructible
- : public is_constructible<_Tp>::type
- { };
+ : public __is_constructible_impl<_Tp>::type
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_copy_constructible_impl;
template<typename _Tp>
struct __is_copy_constructible_impl<_Tp, true>
- : public is_constructible<_Tp, const _Tp&>
+ : public __is_constructible_impl<_Tp, const _Tp&>
{ };
/// is_copy_constructible
template<typename _Tp>
struct is_copy_constructible
: public __is_copy_constructible_impl<_Tp>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_move_constructible_impl;
template<typename _Tp>
struct __is_move_constructible_impl<_Tp, true>
- : public is_constructible<_Tp, _Tp&&>
+ : public __is_constructible_impl<_Tp, _Tp&&>
{ };
/// is_move_constructible
template<typename _Tp>
struct is_move_constructible
: public __is_move_constructible_impl<_Tp>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp>
struct __is_nt_default_constructible_atom
: public __is_nt_default_constructible_atom<_Tp>
{ };
+ template<typename _Tp>
+ using __is_nothrow_default_constructible_impl
+ = __and_<__is_constructible_impl<_Tp>,
+ __is_nt_default_constructible_impl<_Tp>>;
+
/// is_nothrow_default_constructible
template<typename _Tp>
struct is_nothrow_default_constructible
- : public __and_<is_default_constructible<_Tp>,
- __is_nt_default_constructible_impl<_Tp>>
- { };
+ : public __is_nothrow_default_constructible_impl<_Tp>::type
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp, typename... _Args>
struct __is_nt_constructible_impl
template<typename _Tp>
struct __is_nt_constructible_impl<_Tp>
- : public is_nothrow_default_constructible<_Tp>
+ : public __is_nothrow_default_constructible_impl<_Tp>
{ };
- /// is_nothrow_constructible
template<typename _Tp, typename... _Args>
- struct is_nothrow_constructible
- : public __and_<is_constructible<_Tp, _Args...>,
+ struct __is_nothrow_constructible_impl
+ : public __and_<__is_constructible_impl<_Tp, _Args...>,
__is_nt_constructible_impl<_Tp, _Args...>>
{ };
+ /// is_nothrow_constructible
+ template<typename _Tp, typename... _Args>
+ struct is_nothrow_constructible
+ : public __is_nothrow_constructible_impl<_Tp, _Args...>::type
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
+
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_nothrow_copy_constructible_impl;
template<typename _Tp>
struct __is_nothrow_copy_constructible_impl<_Tp, true>
- : public is_nothrow_constructible<_Tp, const _Tp&>
+ : public __is_nothrow_constructible_impl<_Tp, const _Tp&>
{ };
/// is_nothrow_copy_constructible
template<typename _Tp>
struct is_nothrow_copy_constructible
- : public __is_nothrow_copy_constructible_impl<_Tp>
- { };
+ : public __is_nothrow_copy_constructible_impl<_Tp>::type
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_nothrow_move_constructible_impl;
template<typename _Tp>
struct __is_nothrow_move_constructible_impl<_Tp, true>
- : public is_nothrow_constructible<_Tp, _Tp&&>
+ : public __is_nothrow_constructible_impl<_Tp, _Tp&&>
{ };
/// is_nothrow_move_constructible
template<typename _Tp>
struct is_nothrow_move_constructible
- : public __is_nothrow_move_constructible_impl<_Tp>
- { };
+ : public __is_nothrow_move_constructible_impl<_Tp>::type
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// is_assignable
template<typename _Tp, typename _Up>
struct is_assignable
- : public __bool_constant<__is_assignable(_Tp, _Up)>
- { };
+ : public __bool_constant<__is_assignable(_Tp, _Up)>
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_copy_assignable_impl;
template<typename _Tp>
struct __is_copy_assignable_impl<_Tp, true>
- : public is_assignable<_Tp&, const _Tp&>
+ : public __bool_constant<__is_assignable(_Tp&, const _Tp&)>
{ };
/// is_copy_assignable
template<typename _Tp>
struct is_copy_assignable
- : public __is_copy_assignable_impl<_Tp>
- { };
+ : public __is_copy_assignable_impl<_Tp>::type
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_move_assignable_impl;
template<typename _Tp>
struct __is_move_assignable_impl<_Tp, true>
- : public is_assignable<_Tp&, _Tp&&>
+ : public __bool_constant<__is_assignable(_Tp&, _Tp&&)>
{ };
/// is_move_assignable
template<typename _Tp>
struct is_move_assignable
- : public __is_move_assignable_impl<_Tp>
- { };
+ : public __is_move_assignable_impl<_Tp>::type
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp, typename _Up>
struct __is_nt_assignable_impl
: public integral_constant<bool, noexcept(declval<_Tp>() = declval<_Up>())>
{ };
- /// is_nothrow_assignable
template<typename _Tp, typename _Up>
- struct is_nothrow_assignable
- : public __and_<is_assignable<_Tp, _Up>,
+ struct __is_nothrow_assignable_impl
+ : public __and_<__bool_constant<__is_assignable(_Tp, _Up)>,
__is_nt_assignable_impl<_Tp, _Up>>
{ };
+ /// is_nothrow_assignable
+ template<typename _Tp, typename _Up>
+ struct is_nothrow_assignable
+ : public __is_nothrow_assignable_impl<_Tp, _Up>
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
+
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_nt_copy_assignable_impl;
template<typename _Tp>
struct __is_nt_copy_assignable_impl<_Tp, true>
- : public is_nothrow_assignable<_Tp&, const _Tp&>
+ : public __is_nothrow_assignable_impl<_Tp&, const _Tp&>
{ };
/// is_nothrow_copy_assignable
template<typename _Tp>
struct is_nothrow_copy_assignable
: public __is_nt_copy_assignable_impl<_Tp>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_nt_move_assignable_impl;
template<typename _Tp>
struct __is_nt_move_assignable_impl<_Tp, true>
- : public is_nothrow_assignable<_Tp&, _Tp&&>
+ : public __is_nothrow_assignable_impl<_Tp&, _Tp&&>
{ };
/// is_nothrow_move_assignable
template<typename _Tp>
struct is_nothrow_move_assignable
: public __is_nt_move_assignable_impl<_Tp>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// is_trivially_constructible
template<typename _Tp, typename... _Args>
struct is_trivially_constructible
: public __bool_constant<__is_trivially_constructible(_Tp, _Args...)>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// is_trivially_default_constructible
template<typename _Tp>
struct is_trivially_default_constructible
- : public is_trivially_constructible<_Tp>::type
- { };
+ : public __bool_constant<__is_trivially_constructible(_Tp)>
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
struct __do_is_implicitly_default_constructible_impl
{
template <typename _Tp>
struct __is_implicitly_default_constructible
- : public __and_<is_default_constructible<_Tp>,
+ : public __and_<__is_constructible_impl<_Tp>,
__is_implicitly_default_constructible_safe<_Tp>>
{ };
- /// is_trivially_copy_constructible
-
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_trivially_copy_constructible_impl;
template<typename _Tp>
struct __is_trivially_copy_constructible_impl<_Tp, true>
- : public __and_<is_copy_constructible<_Tp>,
+ : public __and_<__is_copy_constructible_impl<_Tp>,
integral_constant<bool,
__is_trivially_constructible(_Tp, const _Tp&)>>
{ };
+ /// is_trivially_copy_constructible
template<typename _Tp>
struct is_trivially_copy_constructible
: public __is_trivially_copy_constructible_impl<_Tp>
- { };
-
- /// is_trivially_move_constructible
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_trivially_move_constructible_impl;
template<typename _Tp>
struct __is_trivially_move_constructible_impl<_Tp, true>
- : public __and_<is_move_constructible<_Tp>,
+ : public __and_<__is_move_constructible_impl<_Tp>,
integral_constant<bool,
__is_trivially_constructible(_Tp, _Tp&&)>>
{ };
+ /// is_trivially_move_constructible
template<typename _Tp>
struct is_trivially_move_constructible
: public __is_trivially_move_constructible_impl<_Tp>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// is_trivially_assignable
template<typename _Tp, typename _Up>
struct is_trivially_assignable
: public __bool_constant<__is_trivially_assignable(_Tp, _Up)>
- { };
-
- /// is_trivially_copy_assignable
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_trivially_copy_assignable_impl;
: public __bool_constant<__is_trivially_assignable(_Tp&, const _Tp&)>
{ };
+ /// is_trivially_copy_assignable
template<typename _Tp>
struct is_trivially_copy_assignable
: public __is_trivially_copy_assignable_impl<_Tp>
- { };
-
- /// is_trivially_move_assignable
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_trivially_move_assignable_impl;
: public __bool_constant<__is_trivially_assignable(_Tp&, _Tp&&)>
{ };
+ /// is_trivially_move_assignable
template<typename _Tp>
struct is_trivially_move_assignable
: public __is_trivially_move_assignable_impl<_Tp>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// is_trivially_destructible
template<typename _Tp>
struct is_trivially_destructible
- : public __and_<is_destructible<_Tp>,
+ : public __and_<__is_destructible_safe<_Tp>,
__bool_constant<__has_trivial_destructor(_Tp)>>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// has_virtual_destructor
template<typename _Tp>
struct has_virtual_destructor
: public integral_constant<bool, __has_virtual_destructor(_Tp)>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
// type property queries.
/// alignment_of
template<typename _Tp>
struct alignment_of
- : public integral_constant<std::size_t, alignof(_Tp)> { };
+ : public integral_constant<std::size_t, alignof(_Tp)>
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// rank
template<typename>
: public __is_convertible_helper<_From, _To>::type
{ };
- template<typename _From, typename _To,
+ template<typename _From, typename _To,
bool = __or_<is_void<_From>, is_function<_To>,
is_array<_To>>::value>
struct __is_nt_convertible_helper
template<typename _Tp>
struct is_swappable
: public __is_swappable_impl<_Tp>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// is_nothrow_swappable
template<typename _Tp>
struct is_nothrow_swappable
: public __is_nothrow_swappable_impl<_Tp>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
#if __cplusplus >= 201402L
/// is_swappable_v
template<typename _Fn, typename... _ArgTypes>
struct is_invocable
: __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
+ "_Fn must be a complete class or an unbounded array");
+ };
/// std::is_invocable_r
template<typename _Ret, typename _Fn, typename... _ArgTypes>
struct is_invocable_r
: __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
+ "_Fn must be a complete class or an unbounded array");
+ };
/// std::is_nothrow_invocable
template<typename _Fn, typename... _ArgTypes>
struct is_nothrow_invocable
: __and_<__is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>,
- __call_is_nothrow_<_Fn, _ArgTypes...>>::type
- { };
+ __call_is_nothrow_<_Fn, _ArgTypes...>>::type
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
+ "_Fn must be a complete class or an unbounded array");
+ };
template<typename _Result, typename _Ret, typename = void>
struct __is_nt_invocable_impl : false_type { };
: bool_constant<__has_unique_object_representations(
remove_cv_t<remove_all_extents_t<_Tp>>
)>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
template<typename _Tp>
inline constexpr bool has_unique_object_representations_v
/// is_aggregate
template<typename _Tp>
struct is_aggregate
- : bool_constant<__is_aggregate(remove_cv_t<_Tp>)> { };
+ : bool_constant<__is_aggregate(remove_cv_t<_Tp>)>
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// is_aggregate_v
template<typename _Tp>
--- /dev/null
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <type_traits>
+
+
+struct incomplete_type;
+class incomplete_type2;
+union incomplete_union;
+enum class incomplete_enum: int;
+enum incomplete_enum2: int;
+static_assert(!std::__is_complete_or_unbounded(std::__type_identity<incomplete_type>{}), "");
+static_assert(!std::__is_complete_or_unbounded(std::__type_identity<incomplete_type2>{}), "");
+static_assert(!std::__is_complete_or_unbounded(std::__type_identity<incomplete_union>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<incomplete_enum>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<incomplete_enum2>{}), "");
+
+static_assert(!std::__is_complete_or_unbounded(std::__type_identity<incomplete_type[42]>{}), "");
+static_assert(!std::__is_complete_or_unbounded(std::__type_identity<incomplete_type2[42]>{}), "");
+static_assert(!std::__is_complete_or_unbounded(std::__type_identity<incomplete_union[42]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<incomplete_enum[42]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<incomplete_enum2[42]>{}), "");
+
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<incomplete_type[]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<incomplete_type2[]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<incomplete_union[]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<incomplete_enum[]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<incomplete_enum2[]>{}), "");
+
+
+struct complete_type{ ~complete_type() = delete; };
+class complete_type2{ int i; };
+union complete_union{};
+enum class complete_enum: int {};
+enum complete_enum2: int {};
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_type>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_type2>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_union>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_enum>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_enum2>{}), "");
+
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_type[42]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_type2[42]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_union[42]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_enum[42]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_enum2[42]>{}), "");
+
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_type[]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_type2[]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_union[]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_enum[]>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_enum2[]>{}), "");
+
+
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<const complete_type>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<const complete_type2>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<const complete_union>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<const complete_enum>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<const complete_enum2>{}), "");
+
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<incomplete_type*>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_type*>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<const incomplete_type*>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<const complete_type*>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<incomplete_type&>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_type&>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<incomplete_type&&>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<complete_type&&>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<int complete_type::*>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<int (complete_type::*)(int)>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<int incomplete_type::*>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<int (incomplete_type::*)(int)>{}), "");
+
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<void(*)() noexcept>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<void(...) noexcept>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<void(&)(int)>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<void(*)()>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<void(incomplete_type)>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<void(&)()>{}), "");
+
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<std::nullptr_t>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<void>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<void*>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<const void* const>{}), "");