This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type


This patch adds static asserts for type traits misuse with incomplete
classes and unions. This gives a nice readable error message instead
of an UB and odr-violations.

Some features of the patch:
* each type trait has it's own static_assert inside. This gives better
diagnostics than the approach with putting the assert into a helper
structure and using it in each trait.
* the result of completeness check is not memorized by the compiler.
This gives no false positive after the first failed check.
* some of the compiler builtins already implement the check. But not
all of them! So the asserts are in all the type_traits that may
benefit from the check. This also makes the behavior of libstdc++ more
consistent across different (non GCC) compilers.
* std::is_base_of does not have the assert as it works well in many
cases with incomplete types

PR libstdc++/71579
    * include/std/type_traits: Add static_asserts to make sure that
    type traits are not misused with an incomplete type.
    * testsuite/20_util/__is_complete_or_unbounded/memoization.cc:
    New test.
    * testsuite/20_util/__is_complete_or_unbounded/memoization_neg.cc:
    Likewise.
    * testsuite/20_util/__is_complete_or_unbounded/value.cc: Likewise.
    * testsuite/20_util/is_abstract/incomplete_neg.cc: Likewise.
    * testsuite/20_util/is_aggregate/incomplete_neg.cc: Likewise.
    * testsuite/20_util/is_class/value.cc: Likewise.
    * testsuite/20_util/is_function/value.cc: Likewise.
    * testsuite/20_util/is_move_constructible/incomplete_neg.cc: Likewise.
    * testsuite/20_util/is_nothrow_move_assignable/incomplete_neg.cc:
    Likewise.
    * testsuite/20_util/is_polymorphic/incomplete_neg.cc: Likewise.
    * testsuite/20_util/is_reference/value.cc: Likewise.
    * testsuite/20_util/is_unbounded_array/value.cc: Likewise.
    * testsuite/20_util/is_union/value.cc: Likewise.
    * testsuite/20_util/is_void/value.cc: Likewise.
    * testsuite/util/testsuite_tr1.h: Add incomplete union type.

-- 
Best regards,
Antony Polukhin
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 411eff1..3a0cf44 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,27 @@
+2019-05-06  Antony Polukhin  <antoshkka@gmail.com>
+
+	PR libstdc++/71579
+	* include/std/type_traits: Add static_asserts to make sure that
+	type traits are not misused with an incomplete type.
+	* testsuite/20_util/__is_complete_or_unbounded/memoization.cc:
+	New test.
+	* testsuite/20_util/__is_complete_or_unbounded/memoization_neg.cc:
+	Likewise.
+	* testsuite/20_util/__is_complete_or_unbounded/value.cc: Likewise.
+	* testsuite/20_util/is_abstract/incomplete_neg.cc: Likewise.
+	* testsuite/20_util/is_aggregate/incomplete_neg.cc: Likewise.
+	* testsuite/20_util/is_class/value.cc: Likewise.
+	* testsuite/20_util/is_function/value.cc: Likewise.
+	* testsuite/20_util/is_move_constructible/incomplete_neg.cc: Likewise.
+	* testsuite/20_util/is_nothrow_move_assignable/incomplete_neg.cc:
+	Likewise.
+	* testsuite/20_util/is_polymorphic/incomplete_neg.cc: Likewise.
+	* testsuite/20_util/is_reference/value.cc: Likewise.
+	* testsuite/20_util/is_unbounded_array/value.cc: Likewise.
+	* testsuite/20_util/is_union/value.cc: Likewise.
+	* testsuite/20_util/is_void/value.cc: Likewise.
+	* testsuite/util/testsuite_tr1.h: Add incomplete union type.
+
 2019-05-06  François Dumont  <fdumont@gcc.gnu.org>
 
 	* python/libstdcxx/v6/printers.py (add_one_template_type_printer):
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 1d14c75..6fdb534 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -91,6 +91,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<bool, typename, typename>
     struct conditional;
 
+  template <typename _Type>
+    struct __type_identity {
+      using type = _Type;
+    };
+
   template<typename...>
     struct __or_;
 
@@ -177,6 +182,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #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
@@ -399,9 +431,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 
   template<typename>
-    struct is_function;
-
-  template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
 
@@ -671,44 +700,65 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   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
@@ -716,14 +766,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   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>
@@ -828,7 +884,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   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
@@ -876,7 +935,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   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");
+    };
 
   struct __do_is_default_constructible_impl
   {
@@ -889,10 +951,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _Tp>
     struct __is_default_constructible_impl
-    : public __do_is_default_constructible_impl
-    {
-      typedef decltype(__test<_Tp>(0)) type;
-    };
+    : public decltype(__do_is_default_constructible_impl::__test<_Tp>(0))
+    { };
 
   template<typename _Tp>
     struct __is_default_constructible_atom
@@ -924,14 +984,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_default_constructible
     : public __is_default_constructible_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_constructible
-  template<typename _Tp, typename... _Args>
-    struct is_constructible
+    template<typename _Tp, typename... _Args>
+    struct __is_constructible_impl
       : public __bool_constant<__is_constructible(_Tp, _Args...)>
     { };
 
+  template<typename _Tp, typename... _Args>
+    struct is_constructible
+      : 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");
+    };
+
   template<typename _Tp, bool = __is_referenceable<_Tp>::value>
     struct __is_copy_constructible_impl;
 
@@ -941,14 +1012,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   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;
@@ -959,14 +1033,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   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
@@ -989,12 +1066,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_nothrow_default_constructible
-  template<typename _Tp>
-    struct is_nothrow_default_constructible
-    : public __and_<is_default_constructible<_Tp>,
+    template<typename _Tp>
+    struct __is_nothrow_default_constructible_impl
+    : public __and_<__is_default_constructible_safe<_Tp>,
                     __is_nt_default_constructible_impl<_Tp>>
     { };
 
+  template<typename _Tp>
+    struct is_nothrow_default_constructible
+    : public __is_nothrow_default_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, typename... _Args>
     struct __is_nt_constructible_impl
     : public integral_constant<bool, noexcept(_Tp(declval<_Args>()...))>
@@ -1008,16 +1093,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   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...>>
     { };
 
+  template<typename _Tp, typename... _Args>
+    struct is_nothrow_constructible
+    : public __is_nothrow_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");
+    };
+
   template<typename _Tp, bool = __is_referenceable<_Tp>::value>
     struct __is_nothrow_copy_constructible_impl;
 
@@ -1027,14 +1120,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   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>
-    { };
+    {
+      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;
@@ -1045,20 +1141,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   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>
-    { };
+    {
+      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)>
-    { };
+    {
+      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;
@@ -1069,14 +1171,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   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>
-    { };
+    {
+      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;
@@ -1087,14 +1192,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   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>
-    { };
+    {
+      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
@@ -1102,12 +1210,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_nothrow_assignable
-  template<typename _Tp, typename _Up>
-    struct is_nothrow_assignable
-    : public __and_<is_assignable<_Tp, _Up>,
+    template<typename _Tp, typename _Up>
+    struct __is_nothrow_assignable_impl
+    : public __and_<__bool_constant<__is_assignable(_Tp, _Up)>,
 		    __is_nt_assignable_impl<_Tp, _Up>>
     { };
 
+  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;
 
@@ -1117,14 +1233,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   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;
@@ -1135,26 +1254,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   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
   {
@@ -1182,7 +1310,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template <typename _Tp>
     struct __is_implicitly_default_constructible
-    : public __and_<is_default_constructible<_Tp>,
+    : public __and_<__is_default_constructible_safe<_Tp>,
 		    __is_implicitly_default_constructible_safe<_Tp>>
     { };
 
@@ -1197,7 +1325,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   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&)>>
     { };
@@ -1205,7 +1333,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_trivially_copy_constructible
     : public __is_trivially_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");
+    };
 
   /// is_trivially_move_constructible
 
@@ -1218,7 +1349,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   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&&)>>
     { };
@@ -1226,13 +1357,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   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)>
-    { };
+    {
+      static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+	"template argument must be a complete class or an unbounded array");
+    };
 
   /// is_trivially_copy_assignable
 
@@ -1251,7 +1388,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_trivially_copy_assignable
     : public __is_trivially_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");
+    };
 
   /// is_trivially_move_assignable
 
@@ -1270,21 +1410,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   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.
@@ -1292,7 +1441,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// 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>
@@ -2596,13 +2749,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   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
@@ -2793,20 +2952,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   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 { };
@@ -3013,7 +3181,10 @@ template <typename _From, typename _To>
     : 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
@@ -3025,7 +3196,11 @@ template <typename _From, typename _To>
   /// 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>
@@ -3084,7 +3259,7 @@ template <typename _From, typename _To>
     : public __is_array_known_bounds<_Tp>
     { };
 
-  /// True for a type that is an array of unknown bound.
+  /// True for a type that is an unbounded array.
   template<typename _Tp>
     struct is_unbounded_array
     : public __is_array_unknown_bounds<_Tp>
diff --git a/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/memoization.cc b/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/memoization.cc
new file mode 100644
index 0000000..83afb40
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/memoization.cc
@@ -0,0 +1,29 @@
+// { 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 X;
+static_assert(
+  !std::__is_complete_or_unbounded(std::__type_identity<X>{}), "error");
+
+struct X{};
+static_assert(
+  std::__is_complete_or_unbounded(std::__type_identity<X>{}),
+  "Result memoized. This leads to worse diagnostics");
diff --git a/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/memoization_neg.cc b/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/memoization_neg.cc
new file mode 100644
index 0000000..04b83a2
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/memoization_neg.cc
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++11 } }
+// { dg-prune-output "must be a complete" }
+
+// 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 X;
+constexpr bool res_incomplete = std::is_move_constructible<X>::value; // { dg-error "required from here" }
+
+struct X{};
+constexpr bool res_complete = std::is_default_constructible<X>::value; // { dg-bogus "required from here" }
diff --git a/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/value.cc b/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/value.cc
new file mode 100644
index 0000000..5a03ad6
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/value.cc
@@ -0,0 +1,100 @@
+// { 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>{}), "");
diff --git a/libstdc++-v3/testsuite/20_util/is_abstract/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_abstract/incomplete_neg.cc
new file mode 100644
index 0000000..94f4ecd
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_abstract/incomplete_neg.cc
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++11 } }
+// { dg-prune-output "invalid use of incomplete type" }
+// { dg-prune-output "must be a complete" }
+//
+// 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>
+
+class X;
+
+void test01()
+{
+  std::is_abstract<X>();		// { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_aggregate/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_aggregate/incomplete_neg.cc
new file mode 100644
index 0000000..8a3dd55
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_aggregate/incomplete_neg.cc
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++17 } }
+//
+// 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/>.
+
+// { dg-error "must be a complete class" "" { target *-*-* } 0 }
+
+#include <type_traits>
+
+class X;
+
+void test01()
+{
+  std::is_aggregate<X>();		// { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_class/value.cc b/libstdc++-v3/testsuite/20_util/is_class/value.cc
index 6391e28..801dc67 100644
--- a/libstdc++-v3/testsuite/20_util/is_class/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_class/value.cc
@@ -27,6 +27,7 @@ void test01()
 
   // Positive tests.
   static_assert(test_category<is_class, ClassType>(true), "");
+  static_assert(test_category<is_class, IncompleteClass>(true), "");
   static_assert(test_category<is_class, DerivedType>(true), "");
   static_assert(test_category<is_class, ConvType>(true), "");
   static_assert(test_category<is_class, AbstractClass>(true), "");
@@ -47,4 +48,5 @@ void test01()
   static_assert(test_category<is_class, int (ClassType::*) (int)>(false), "");
   static_assert(test_category<is_class, int (int)>(false), "");
   static_assert(test_category<is_class, EnumType>(false), "");
+  static_assert(test_category<is_class, IncompleteUnion>(false), "");
 }
diff --git a/libstdc++-v3/testsuite/20_util/is_function/value.cc b/libstdc++-v3/testsuite/20_util/is_function/value.cc
index cef2e3d..7b94b58 100644
--- a/libstdc++-v3/testsuite/20_util/is_function/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_function/value.cc
@@ -46,4 +46,6 @@ void test01()
   
   // Sanity check.
   static_assert(test_category<is_function, ClassType>(false), "");
+  static_assert(test_category<is_function, IncompleteClass>(false), "");
+  static_assert(test_category<is_function, IncompleteUnion>(false), "");
 }
diff --git a/libstdc++-v3/testsuite/20_util/is_move_constructible/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_move_constructible/incomplete_neg.cc
new file mode 100644
index 0000000..d6a08d7
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_move_constructible/incomplete_neg.cc
@@ -0,0 +1,29 @@
+// { 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/>.
+
+// { dg-error "must be a complete class" "" { target *-*-* } 0 }
+
+#include <type_traits>
+
+class X;
+
+void test01()
+{
+  std::is_move_constructible<X>();		// { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_move_assignable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_move_assignable/incomplete_neg.cc
new file mode 100644
index 0000000..ebceec5
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_move_assignable/incomplete_neg.cc
@@ -0,0 +1,29 @@
+// { 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/>.
+
+// { dg-error "must be a complete class" "" { target *-*-* } 0 }
+
+#include <type_traits>
+
+class X;
+
+void test01()
+{
+  std::is_nothrow_move_assignable<X>();		// { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_polymorphic/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_polymorphic/incomplete_neg.cc
new file mode 100644
index 0000000..8cd1b40
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_polymorphic/incomplete_neg.cc
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++11 } }
+// { dg-prune-output "invalid use of incomplete type" }
+// { dg-prune-output "must be a complete" }
+//
+// 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>
+
+class X;
+
+void test01()
+{
+  std::is_polymorphic<X>();		// { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_reference/value.cc b/libstdc++-v3/testsuite/20_util/is_reference/value.cc
index 79a9973..4676894 100644
--- a/libstdc++-v3/testsuite/20_util/is_reference/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_reference/value.cc
@@ -33,8 +33,11 @@ void test01()
   static_assert(test_category<is_reference, int&&>(true), "");
   static_assert(test_category<is_reference, ClassType&&>(true), "");
   static_assert(test_category<is_reference, int(&&)(int)>(true), "");
+  static_assert(test_category<is_reference, IncompleteClass&>(true), "");
+  static_assert(test_category<is_reference, const IncompleteClass&>(true), "");
 
   // Sanity check.
   static_assert(test_category<is_reference, ClassType>(false), "");
+  static_assert(test_category<is_reference, IncompleteClass>(false), "");
 }
 
diff --git a/libstdc++-v3/testsuite/20_util/is_unbounded_array/value.cc b/libstdc++-v3/testsuite/20_util/is_unbounded_array/value.cc
index 19fb052..bca0e3c 100644
--- a/libstdc++-v3/testsuite/20_util/is_unbounded_array/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_unbounded_array/value.cc
@@ -44,6 +44,8 @@ void test01()
   static_assert(test_category<is_unbounded_array, ClassType[]>(true), "");
   static_assert(test_category<is_unbounded_array, ClassType[2][3]>(false), "");
   static_assert(test_category<is_unbounded_array, ClassType[][3]>(true), "");
+  static_assert(test_category<is_unbounded_array, IncompleteClass[2][3]>(false), "");
+  static_assert(test_category<is_unbounded_array, IncompleteClass[][3]>(true), "");
   static_assert(test_category<is_unbounded_array, int(*)[2]>(false), "");
   static_assert(test_category<is_unbounded_array, int(*)[]>(false), "");
   static_assert(test_category<is_unbounded_array, int(&)[2]>(false), "");
@@ -51,6 +53,8 @@ void test01()
 
   // Sanity check.
   static_assert(test_category<is_unbounded_array, ClassType>(false), "");
+  static_assert(test_category<is_unbounded_array, IncompleteClass>(false), "");
+  static_assert(test_category<is_unbounded_array, IncompleteUnion>(false), "");
 }
 
 template <class... T> void pos()
diff --git a/libstdc++-v3/testsuite/20_util/is_union/value.cc b/libstdc++-v3/testsuite/20_util/is_union/value.cc
index 7d0f201..54df151 100644
--- a/libstdc++-v3/testsuite/20_util/is_union/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_union/value.cc
@@ -27,6 +27,7 @@ void test01()
 
   // Positive tests.
   static_assert(test_category<is_union, UnionType>(true), "");
+  static_assert(test_category<is_union, IncompleteUnion>(true), "");
 
   // Negative tests.
   static_assert(test_category<is_union, ClassType>(false), "");
@@ -47,4 +48,5 @@ void test01()
   static_assert(test_category<is_union, int (ClassType::*) (int)>(false), "");
   static_assert(test_category<is_union, int (int)>(false), "");
   static_assert(test_category<is_union, EnumType>(false), "");
+  static_assert(test_category<is_union, IncompleteClass>(false), "");
 }
diff --git a/libstdc++-v3/testsuite/20_util/is_void/value.cc b/libstdc++-v3/testsuite/20_util/is_void/value.cc
index f04cdd6..dc116f7 100644
--- a/libstdc++-v3/testsuite/20_util/is_void/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_void/value.cc
@@ -47,4 +47,6 @@ void test01()
 
   // Sanity check.
   static_assert(test_category<is_void, ClassType>(false), "");
+  static_assert(test_category<is_void, IncompleteClass>(false), "");
+  static_assert(test_category<is_void, IncompleteUnion>(false), "");
 }
diff --git a/libstdc++-v3/testsuite/util/testsuite_tr1.h b/libstdc++-v3/testsuite/util/testsuite_tr1.h
index b431682..2e1cbb0 100644
--- a/libstdc++-v3/testsuite/util/testsuite_tr1.h
+++ b/libstdc++-v3/testsuite/util/testsuite_tr1.h
@@ -126,6 +126,8 @@ namespace __gnu_test
 
   union UnionType { };
 
+  union IncompleteUnion;
+
   class IncompleteClass;
 
   struct ExplicitClass

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]