* [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
@ 2019-05-06 11:20 Antony Polukhin
2019-05-08 21:10 ` Jonathan Wakely
0 siblings, 1 reply; 20+ messages in thread
From: Antony Polukhin @ 2019-05-06 11:20 UTC (permalink / raw)
To: libstdc++, gcc-patches List
[-- Attachment #1: Type: text/plain, Size: 2025 bytes --]
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
[-- Attachment #2: type_traits_hardening.patch --]
[-- Type: text/x-patch, Size: 46983 bytes --]
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
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2019-05-06 11:20 [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type Antony Polukhin
@ 2019-05-08 21:10 ` Jonathan Wakely
2019-05-30 6:07 ` Antony Polukhin
0 siblings, 1 reply; 20+ messages in thread
From: Jonathan Wakely @ 2019-05-08 21:10 UTC (permalink / raw)
To: Antony Polukhin; +Cc: libstdc++, gcc-patches List
On 06/05/19 14:19 +0300, Antony Polukhin wrote:
>@@ -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
This "///" comment is for Doxygen, and should remain with the
is_constructible trait, not __is_constructible_impl.
>- 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;
>
The rest looks reasonable, but I'll finish reviewing it ASAP, when I
have more time.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2019-05-08 21:10 ` Jonathan Wakely
@ 2019-05-30 6:07 ` Antony Polukhin
2019-05-30 16:38 ` Jonathan Wakely
0 siblings, 1 reply; 20+ messages in thread
From: Antony Polukhin @ 2019-05-30 6:07 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: libstdc++, gcc-patches List
[-- Attachment #1: Type: text/plain, Size: 842 bytes --]
чт, 9 мая 2019 г. в 00:10, Jonathan Wakely <jwakely@redhat.com>:
>
> On 06/05/19 14:19 +0300, Antony Polukhin wrote:
> >@@ -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
>
> This "///" comment is for Doxygen, and should remain with the
> is_constructible trait, not __is_constructible_impl.
Fixed that issue along with some other misplaced Doxygen comments.
Rebased the patch and removed some trailing white-spaces.
--
Best regards,
Antony Polukhin
[-- Attachment #2: type_traits_hardening.txt --]
[-- Type: text/plain, Size: 47074 bytes --]
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index b209460..c5f0672 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,27 @@
+2019-05-29 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-29 Jonathan Wakely <jwakely@redhat.com>
* testsuite/util/testsuite_api.h: Remove names of unused parameters.
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 3a622eb..b481106 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,19 +935,38 @@ _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");
+ };
+
+ 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");
+ };
+
+ template<typename _Tp>
+ struct __is_default_constructible_impl
+ : public __is_constructible_impl<_Tp>::type
{ };
/// is_default_constructible
template<typename _Tp>
struct is_default_constructible
- : public is_constructible<_Tp>::type
- { };
+ : public __is_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, bool = __is_referenceable<_Tp>::value>
struct __is_copy_constructible_impl;
@@ -899,14 +977,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;
@@ -917,14 +998,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
@@ -946,12 +1030,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public __is_nt_default_constructible_atom<_Tp>
{ };
+ template<typename _Tp>
+ struct __is_nothrow_default_constructible_impl
+ : public __and_<__is_default_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>
+ {
+ 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
@@ -966,16 +1058,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...>>
{ };
+ /// is_nothrow_constructible
+ 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;
@@ -985,14 +1085,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;
@@ -1003,20 +1106,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;
@@ -1027,14 +1136,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;
@@ -1045,26 +1157,37 @@ _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
: public integral_constant<bool, noexcept(declval<_Tp>() = declval<_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>>
+ { };
+
/// is_nothrow_assignable
template<typename _Tp, typename _Up>
struct is_nothrow_assignable
- : public __and_<is_assignable<_Tp, _Up>,
- __is_nt_assignable_impl<_Tp, _Up>>
- { };
+ : 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;
@@ -1075,14 +1198,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;
@@ -1093,26 +1219,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
{
@@ -1140,12 +1275,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template <typename _Tp>
struct __is_implicitly_default_constructible
- : public __and_<is_default_constructible<_Tp>,
+ : public __and_<__is_default_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;
@@ -1155,17 +1288,19 @@ _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&)>>
{ };
+ /// 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;
@@ -1176,23 +1311,28 @@ _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&&)>>
{ };
+ /// 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;
@@ -1206,12 +1346,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: 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;
@@ -1225,24 +1367,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: 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.
@@ -1250,7 +1402,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>
@@ -2577,13 +2733,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
@@ -2774,20 +2936,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 { };
@@ -2993,7 +3164,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
@@ -3005,7 +3179,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>
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
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2019-05-30 6:07 ` Antony Polukhin
@ 2019-05-30 16:38 ` Jonathan Wakely
2019-05-31 5:58 ` Antony Polukhin
0 siblings, 1 reply; 20+ messages in thread
From: Jonathan Wakely @ 2019-05-30 16:38 UTC (permalink / raw)
To: Antony Polukhin; +Cc: libstdc++, gcc-patches List
[-- Attachment #1: Type: text/plain, Size: 5162 bytes --]
On 30/05/19 09:06 +0300, Antony Polukhin wrote:
>ÑÑ, 9 Ð¼Ð°Ñ 2019 г. в 00:10, Jonathan Wakely <jwakely@redhat.com>:
>>
>> On 06/05/19 14:19 +0300, Antony Polukhin wrote:
>> >@@ -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
>>
>> This "///" comment is for Doxygen, and should remain with the
>> is_constructible trait, not __is_constructible_impl.
>
>Fixed that issue along with some other misplaced Doxygen comments.
>Rebased the patch and removed some trailing white-spaces.
Thanks! Rebasing this was on my TODO list for today.
>--
>Best regards,
>Antony Polukhin
>diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
>index b209460..c5f0672 100644
>--- a/libstdc++-v3/ChangeLog
>+++ b/libstdc++-v3/ChangeLog
>@@ -1,3 +1,27 @@
>+2019-05-29 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.
This changelog could be more explicit. It doesn't have to list every
changed trait, but maybe something like:
* include/std/type_traits: Add static_asserts to make sure that
type traits are not misused with an incomplete type. Create
new base characteristics without assertions that can be reused
in other traits.
>+ * 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.
I think I'd prefer not to have the double underscores in the directory
name here.
>@@ -876,19 +935,38 @@ _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");
>+ };
>+
>+ template<typename _Tp, typename... _Args>
N.B. This 'template' keyword should only be indented two spaces,
however ...
>+ struct __is_constructible_impl
>+ : public __bool_constant<__is_constructible(_Tp, _Args...)>
> { };
I thought this could be an alias template instead of a class template:
template<typename _Tp, typename... _Args>
using __is_constructible_impl
= __bool_constant<__is_constructible(_Tp, _Args...)>;
But it causes failures in the 20_util/variable_templates_for_traits.cc
test. It looks like it instantiates some things too eagerly if it's an
alias template.
> /// 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");
>+ };
>+
>+ template<typename _Tp>
>+ struct __is_default_constructible_impl
>+ : public __is_constructible_impl<_Tp>::type
> { };
Do we need this new __is_default_constructible_impl type?
Could we just use __is_constructible_impl<_Tp> instead, to avoid an
extra step (and extra template instantiations)?
>@@ -946,12 +1030,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> : public __is_nt_default_constructible_atom<_Tp>
> { };
>
>+ template<typename _Tp>
Indentation again :-)
>+ struct __is_nothrow_default_constructible_impl
>+ : public __and_<__is_default_constructible_impl<_Tp>,
>+ __is_nt_default_constructible_impl<_Tp>>
>+ { };
This one can be an alias template:
template<typename _Tp>
using __is_nothrow_default_constructible_impl
= typename __and_<__is_constructible_impl<_Tp>,
__is_nt_default_constructible_impl<_Tp>>::type;
>+ template<typename _Tp, typename _Up>
>+ struct __is_nothrow_assignable_impl
>+ : public __and_<__bool_constant<__is_assignable(_Tp, _Up)>,
>+ __is_nt_assignable_impl<_Tp, _Up>>
>+ { };
I wanted this one to be an alias template:
template<typename _Tp, typename _Up>
using __is_nothrow_assignable_impl
= __and_<__bool_constant<__is_assignable(_Tp, _Up)>,
__is_nt_assignable_impl<_Tp, _Up>>;
But that also causes the same test to fail. I think it would work if
we moved the __is_assignable intrinsic into a new __is_assignable_impl
class template, but then we'd be adding a new class template just to
get rid of another one. That doesn't seem sensible.
I've attached a relative diff, to be applied on top of yours, with my
suggested tweaks. Do you see any issues with it?
(If you're happy with those tweaks I can go ahead and apply this,
there's no need for an updated patch from you).
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 5875 bytes --]
commit 732d9c1c9634900437f560538305a6ffde5d6e8d
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Thu May 30 17:30:45 2019 +0100
simplify
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index b481106b30e..78a113af415 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -940,9 +940,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"template argument must be a complete class or an unbounded array");
};
- template<typename _Tp, typename... _Args>
+ template<typename _Tp, typename... _Args>
struct __is_constructible_impl
- : public __bool_constant<__is_constructible(_Tp, _Args...)>
+ : public __bool_constant<__is_constructible(_Tp, _Args...)>
{ };
/// is_constructible
@@ -954,15 +954,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"template argument must be a complete class or an unbounded array");
};
- template<typename _Tp>
- struct __is_default_constructible_impl
- : public __is_constructible_impl<_Tp>::type
- { };
-
/// is_default_constructible
template<typename _Tp>
struct is_default_constructible
- : public __is_default_constructible_impl<_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");
@@ -1030,16 +1025,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public __is_nt_default_constructible_atom<_Tp>
{ };
- template<typename _Tp>
- struct __is_nothrow_default_constructible_impl
- : public __and_<__is_default_constructible_impl<_Tp>,
- __is_nt_default_constructible_impl<_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 __is_nothrow_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");
@@ -1070,7 +1064,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// is_nothrow_constructible
template<typename _Tp, typename... _Args>
struct is_nothrow_constructible
- : public __is_nothrow_constructible_impl<_Tp, _Args...>
+ : 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");
@@ -1091,7 +1085,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// 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");
@@ -1112,7 +1106,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// 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");
@@ -1121,7 +1115,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// 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");
@@ -1142,7 +1136,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// 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");
@@ -1163,7 +1157,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// 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");
@@ -1174,7 +1168,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public integral_constant<bool, noexcept(declval<_Tp>() = declval<_Up>())>
{ };
- template<typename _Tp, typename _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>>
@@ -1275,7 +1269,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template <typename _Tp>
struct __is_implicitly_default_constructible
- : public __and_<__is_default_constructible_impl<_Tp>,
+ : public __and_<__is_constructible_impl<_Tp>,
__is_implicitly_default_constructible_safe<_Tp>>
{ };
@@ -1492,7 +1486,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: 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
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2019-05-30 16:38 ` Jonathan Wakely
@ 2019-05-31 5:58 ` Antony Polukhin
2019-05-31 10:36 ` Jonathan Wakely
0 siblings, 1 reply; 20+ messages in thread
From: Antony Polukhin @ 2019-05-31 5:58 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: libstdc++, gcc-patches List
On Thu, May 30, 2019, 19:38 Jonathan Wakely <jwakely@redhat.com> wrote:
<...>
> I've attached a relative diff, to be applied on top of yours, with my
> suggested tweaks. Do you see any issues with it?
>
> (If you're happy with those tweaks I can go ahead and apply this,
> there's no need for an updated patch from you).
>
Looks good. Please apply!
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2019-05-31 5:58 ` Antony Polukhin
@ 2019-05-31 10:36 ` Jonathan Wakely
2019-06-06 12:19 ` Jonathan Wakely
0 siblings, 1 reply; 20+ messages in thread
From: Jonathan Wakely @ 2019-05-31 10:36 UTC (permalink / raw)
To: Antony Polukhin; +Cc: libstdc++, gcc-patches List
[-- Attachment #1: Type: text/plain, Size: 511 bytes --]
On 31/05/19 08:58 +0300, Antony Polukhin wrote:
>On Thu, May 30, 2019, 19:38 Jonathan Wakely <jwakely@redhat.com> wrote:
><...>
>
>> I've attached a relative diff, to be applied on top of yours, with my
>> suggested tweaks. Do you see any issues with it?
>>
>> (If you're happy with those tweaks I can go ahead and apply this,
>> there's no need for an updated patch from you).
>>
>
>Looks good. Please apply!
Here's what I've tested and committed to trunk.
I decided to add a more detailed changelog too.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 50176 bytes --]
commit c877256d8a2b0f9383c1cd93c0b2907496c715db
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Fri May 31 09:23:09 2019 +0100
PR libstdc++/71579 assert that type traits are not misused with incomplete types
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
2019-05-31 Antony Polukhin <antoshkka@gmail.com>
PR libstdc++/71579
* include/std/type_traits __type_identity, __is_complete_or_unbounded):
New helpers for checking preconditions in traits.
(is_trivial, is_trivially_copyable, is_standard_layout, is_pod)
(is_literal_type, is_empty, is_polymorphic, is_final, is_abstract)
(is_destructible, is_nothrow_destructible, is_constructible)
(is_default_constructible, is_copy_constructible)
(is_move_constructible, is_nothrow_default_constructible)
(is_nothrow_constructible, is_nothrow_copy_constructible)
(is_nothrow_move_constructible, is_copy_assignable, is_move_assignable)
(is_nothrow_assignable, is_nothrow_copy_assignable)
(is_nothrow_move_assignable, is_trivially_constructible)
(is_trivially_copy_constructible, is_trivially_move_constructible)
is_trivially_assignable, is_trivially_copy_assignable)
(is_trivially_move_assignable, is_trivially_destructible)
(alignment_of, is_swappable, is_nothrow_swappable, is_invocable)
(is_invocable_r, is_nothrow_invocable)
(has_unique_object_representations, is_aggregate): Add static_asserts
to make sure that type traits are not misused with incomplete types.
(__is_constructible_impl, __is_nothrow_default_constructible_impl)
(__is_nothrow_constructible_impl, __is_nothrow_assignable_impl): New
base characteristics without assertions that can be reused in other
traits.
* testsuite/20_util/is_complete_or_unbounded/memoization.cc: New test.
* testsuite/20_util/is_complete_or_unbounded/memoization_neg.cc: New
test.
* testsuite/20_util/is_complete_or_unbounded/value.cc: New test.
* testsuite/20_util/is_abstract/incomplete_neg.cc: New test.
* testsuite/20_util/is_aggregate/incomplete_neg.cc: New test.
* testsuite/20_util/is_class/value.cc: Check incomplete type.
* testsuite/20_util/is_function/value.cc: Likewise.
* testsuite/20_util/is_move_constructible/incomplete_neg.cc: New test.
* testsuite/20_util/is_nothrow_move_assignable/incomplete_neg.cc: New
test.
* testsuite/20_util/is_polymorphic/incomplete_neg.cc: New test.
* testsuite/20_util/is_reference/value.cc: Check incomplete types.
* 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.
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 3a622eb61e0..78a113af415 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
@@ -398,9 +430,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct is_rvalue_reference<_Tp&&>
: 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,19 +935,33 @@ _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");
+ };
+
+ 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;
@@ -899,14 +972,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;
@@ -917,14 +993,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
@@ -946,12 +1025,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: 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
@@ -966,15 +1052,23 @@ _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>
+ { };
+
+ template<typename _Tp, typename... _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 __and_<is_constructible<_Tp, _Args...>,
- __is_nt_constructible_impl<_Tp, _Args...>>
- { };
+ : 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;
@@ -985,14 +1079,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>
- { };
+ : 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;
@@ -1003,20 +1100,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>
- { };
+ : 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;
@@ -1027,14 +1130,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>
- { };
+ : 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;
@@ -1045,26 +1151,37 @@ _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>
- { };
+ : 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>())>
{ };
+ template<typename _Tp, typename _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 __and_<is_assignable<_Tp, _Up>,
- __is_nt_assignable_impl<_Tp, _Up>>
- { };
+ : 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;
@@ -1075,14 +1192,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;
@@ -1093,26 +1213,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
{
@@ -1140,12 +1269,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
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;
@@ -1155,17 +1282,19 @@ _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&)>>
{ };
+ /// 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;
@@ -1176,23 +1305,28 @@ _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&&)>>
{ };
+ /// 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;
@@ -1206,12 +1340,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: 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;
@@ -1225,24 +1361,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: 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.
@@ -1250,7 +1396,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>
@@ -1336,7 +1486,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: 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
@@ -2577,13 +2727,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
@@ -2774,20 +2930,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 { };
@@ -2993,7 +3158,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
@@ -3005,7 +3173,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>
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 00000000000..94f4ecd6000
--- /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 00000000000..8a3dd551cbb
--- /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 6391e286147..801dc679a21 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_complete_or_unbounded/memoization.cc b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization.cc
new file mode 100644
index 00000000000..83afb40cd18
--- /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 00000000000..04b83a21c01
--- /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 00000000000..5a03ad67a30
--- /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_function/value.cc b/libstdc++-v3/testsuite/20_util/is_function/value.cc
index cef2e3de2a1..7b94b58b6cb 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 00000000000..d6a08d77639
--- /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 00000000000..ebceec5474b
--- /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 00000000000..8cd1b402a41
--- /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 79a99737eab..4676894a5e9 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 19fb0524cd8..bca0e3cb82e 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 7d0f2011fca..54df151e025 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 f04cdd61ad7..dc116f7ad09 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 b431682a06e..2e1cbb096b0 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
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2019-05-31 10:36 ` Jonathan Wakely
@ 2019-06-06 12:19 ` Jonathan Wakely
2019-06-20 17:49 ` Antony Polukhin
0 siblings, 1 reply; 20+ messages in thread
From: Jonathan Wakely @ 2019-06-06 12:19 UTC (permalink / raw)
To: Antony Polukhin; +Cc: libstdc++, gcc-patches List
[-- Attachment #1: Type: text/plain, Size: 701 bytes --]
On 31/05/19 11:35 +0100, Jonathan Wakely wrote:
>On 31/05/19 08:58 +0300, Antony Polukhin wrote:
>>On Thu, May 30, 2019, 19:38 Jonathan Wakely <jwakely@redhat.com> wrote:
>><...>
>>
>>>I've attached a relative diff, to be applied on top of yours, with my
>>>suggested tweaks. Do you see any issues with it?
>>>
>>>(If you're happy with those tweaks I can go ahead and apply this,
>>>there's no need for an updated patch from you).
>>>
>>
>>Looks good. Please apply!
>
>Here's what I've tested and committed to trunk.
>
>I decided to add a more detailed changelog too.
I'm removing some of these assertions again, because they are either
reundant or wrong.
Tested x86_64-linux, committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 8483 bytes --]
commit 6ffe4cf371688563be1680ffb75cc1160540cf2e
Author: redi <redi@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Thu Jun 6 12:13:47 2019 +0000
Remove redundant static assertions in [meta.unary.prop] traits
The type property predicates that are implemented by a compiler builtin
already do the right checks in the compiler. The checks for complete
type or unbounded arrays were wrong for these types anyway.
* include/std/type_traits (is_empty, is_polymorphic, is_final)
(is_abstract, is_aggregate): Remove static_assert.
* testsuite/20_util/is_abstract/incomplete_neg.cc: Check for error
from builtin only.
* testsuite/20_util/is_aggregate/incomplete_neg.cc: Likewise. Add
missing -std=gnu++17 option.
* testsuite/20_util/is_empty/incomplete_neg.cc: New test.
* testsuite/20_util/is_final/incomplete_neg.cc: New test.
* testsuite/20_util/is_polymorphic/incomplete_neg.cc: Check for error
from builtin only.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@272000 138bc75d-0d04-0410-961f-82ee72b054a4
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 78a113af415..e53d3c8d535 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -746,19 +746,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
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
@@ -766,20 +760,14 @@ _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>
@@ -3174,10 +3162,7 @@ template <typename _From, typename _To>
template<typename _Tp>
struct is_aggregate
: 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>
diff --git a/libstdc++-v3/testsuite/20_util/is_abstract/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_abstract/incomplete_neg.cc
index 94f4ecd6000..a2a73d01a06 100644
--- a/libstdc++-v3/testsuite/20_util/is_abstract/incomplete_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/is_abstract/incomplete_neg.cc
@@ -1,7 +1,5 @@
// { 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
@@ -19,6 +17,9 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+// Expect the compiler builtin to do the completeness check.
+// { dg-error "incomplete type" "" { target *-*-* } 0 }
+
#include <type_traits>
class X;
diff --git a/libstdc++-v3/testsuite/20_util/is_aggregate/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_aggregate/incomplete_neg.cc
index 8a3dd551cbb..eff3f64c476 100644
--- a/libstdc++-v3/testsuite/20_util/is_aggregate/incomplete_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/is_aggregate/incomplete_neg.cc
@@ -1,5 +1,6 @@
+// { dg-options "-std=gnu++17" }
// { 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
@@ -17,7 +18,8 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-error "must be a complete class" "" { target *-*-* } 0 }
+// Expect the compiler builtin to do the completeness check.
+// { dg-error "incomplete type" "" { target *-*-* } 0 }
#include <type_traits>
diff --git a/libstdc++-v3/testsuite/20_util/is_empty/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_empty/incomplete_neg.cc
new file mode 100644
index 00000000000..3bacefbab7e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_empty/incomplete_neg.cc
@@ -0,0 +1,30 @@
+// { 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/>.
+
+// Expect the compiler builtin to do the completeness check.
+// { dg-error "incomplete type" "" { target *-*-* } 0 }
+
+#include <type_traits>
+
+class X;
+
+void test01()
+{
+ std::is_empty<X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_final/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_final/incomplete_neg.cc
new file mode 100644
index 00000000000..0727c090a83
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_final/incomplete_neg.cc
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++14 } }
+
+// 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/>.
+
+// Expect the compiler builtin to do the completeness check.
+// { dg-error "incomplete type" "" { target *-*-* } 0 }
+
+#include <type_traits>
+
+class X;
+
+void test01()
+{
+ std::is_final<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
index 8cd1b402a41..618c4fa7a9a 100644
--- a/libstdc++-v3/testsuite/20_util/is_polymorphic/incomplete_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/is_polymorphic/incomplete_neg.cc
@@ -1,7 +1,5 @@
// { 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
@@ -19,6 +17,9 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+// Expect the compiler builtin to do the completeness check.
+// { dg-error "incomplete type" "" { target *-*-* } 0 }
+
#include <type_traits>
class X;
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2019-06-06 12:19 ` Jonathan Wakely
@ 2019-06-20 17:49 ` Antony Polukhin
2019-06-20 17:57 ` Ville Voutilainen
0 siblings, 1 reply; 20+ messages in thread
From: Antony Polukhin @ 2019-06-20 17:49 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: libstdc++, gcc-patches List
[-- Attachment #1: Type: text/plain, Size: 494 bytes --]
чт, 6 июн. 2019 г. в 15:19, Jonathan Wakely <jwakely@redhat.com>:
> I'm removing some of these assertions again, because they are either
> reundant or wrong.
Thanks for cleaning up!
In attachment there is an additional patch for type traits hardening.
Things that still remain unasserted are type traits with variadic
template arguments. I have to came up with a proper solution for
providing a useful and lightweight diagnostics.
--
Best regards,
Antony Polukhin
[-- Attachment #2: type_traits_hardening2.txt --]
[-- Type: text/plain, Size: 21703 bytes --]
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index ac98c0d..9063fe5 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,28 @@
+2019-06-20 Antony Polukhin <antoshkka@gmail.com>
+
+ PR libstdc++/71579
+ * include/std/type_traits (is_assignable, is_nothrow_assignable)
+ (is_trivially_assignable, is_nothrow_invocable_r): Add static_asserts
+ to make sure that the second argument of the type trait is not misused
+ with incomplete types.
+ (is_convertible, is_nothrow_convertible, is_swappable_with)
+ (is_nothrow_swappable_with): Add static_asserts to make sure that the
+ first and second arguments of the type trait are not misused with
+ incomplete types.
+ invoke_result: Add static_asserts to make sure that the first argument
+ of the type trait is not misused with incomplete types.
+ * testsuite/20_util/invoke_result/incomplete_neg.cc: New test.
+ * testsuite/20_util/is_assignable/incomplete_neg.cc: New test.
+ * testsuite/20_util/is_convertible/incomplete_neg.cc: New test.
+ * testsuite/20_util/is_nothrow_assignable/incomplete_neg.cc: New test.
+ * testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc: New test.
+ * testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc: New test.
+ * testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc: New
+ test.
+ * testsuite/20_util/is_swappable/incomplete_neg.cc: New test.
+ * testsuite/20_util/is_swappable_with/incomplete_neg.cc: New test.
+ * testsuite/20_util/is_trivially_assignable/incomplete_neg.cc: New test.
+
2019-06-20 Jonathan Wakely <jwakely@redhat.com>
* acinclude.m4 (GLIBCXX_ENABLE_DEBUG): Only do debug build for final
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7d4deb1..77fc94e 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1106,7 +1106,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: 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");
+ "first template argument must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Up>{}),
+ "second template argument must be a complete class or an unbounded array");
};
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
@@ -1168,7 +1170,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: 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");
+ "first template argument must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Up>{}),
+ "second template argument must be a complete class or an unbounded array");
};
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
@@ -1313,7 +1317,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: 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");
+ "first template argument must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Up>{}),
+ "second template argument must be a complete class or an unbounded array");
};
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
@@ -1474,7 +1480,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _From, typename _To>
struct is_convertible
: public __is_convertible_helper<_From, _To>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_From>{}),
+ "first template argument must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_To>{}),
+ "second template argument must be a complete class or an unbounded array");
+ };
template<typename _From, typename _To,
bool = __or_<is_void<_From>, is_function<_To>,
@@ -1516,7 +1527,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _From, typename _To>
struct is_nothrow_convertible
: public __is_nt_convertible_helper<_From, _To>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_From>{}),
+ "_From must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_To>{}),
+ "_To must be a complete class or an unbounded array");
+};
/// is_nothrow_convertible_v
template<typename _From, typename _To>
@@ -2810,13 +2826,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Up>
struct is_swappable_with
: public __is_swappable_with_impl<_Tp, _Up>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "first template argument must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Up>{}),
+ "second template argument must be a complete class or an unbounded array");
+ };
/// is_nothrow_swappable_with
template<typename _Tp, typename _Up>
struct is_nothrow_swappable_with
: public __is_nothrow_swappable_with_impl<_Tp, _Up>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "first template argument must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Up>{}),
+ "second template argument must be a complete class or an unbounded array");
+ };
#if __cplusplus >= 201402L
/// is_swappable_with_v
@@ -2839,7 +2865,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Result, typename _Ret>
struct __is_invocable_impl<_Result, _Ret, __void_t<typename _Result::type>>
- : __or_<is_void<_Ret>, is_convertible<typename _Result::type, _Ret>>::type
+ : __or_<is_void<_Ret>,
+ __is_convertible_helper<typename _Result::type, _Ret>>::type
{ };
template<typename _Fn, typename... _ArgTypes>
@@ -2916,7 +2943,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Functor, typename... _ArgTypes>
struct invoke_result
: public __invoke_result<_Functor, _ArgTypes...>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Functor>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
/// std::invoke_result_t
template<typename _Fn, typename... _Args>
@@ -2965,7 +2995,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct is_nothrow_invocable_r
: __and_<__is_nt_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>,
__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");
+ };
/// std::is_invocable_v
template<typename _Fn, typename... _Args>
diff --git a/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_neg.cc
new file mode 100644
index 0000000..eb06479
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_neg.cc
@@ -0,0 +1,30 @@
+// { 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::invoke_result<X, int>(); // { dg-error "required from here" }
+ std::invoke_result<X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_assignable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_assignable/incomplete_neg.cc
new file mode 100644
index 0000000..f32a087
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_assignable/incomplete_neg.cc
@@ -0,0 +1,31 @@
+// { 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_assignable<X, int>(); // { dg-error "required from here" }
+ std::is_assignable<int, X>(); // { dg-error "required from here" }
+ std::is_assignable<X, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_convertible/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_convertible/incomplete_neg.cc
new file mode 100644
index 0000000..3ffb879
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_convertible/incomplete_neg.cc
@@ -0,0 +1,31 @@
+// { 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_convertible<X, int>(); // { dg-error "required from here" }
+ std::is_convertible<int, X>(); // { dg-error "required from here" }
+ std::is_convertible<X, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_assignable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_assignable/incomplete_neg.cc
new file mode 100644
index 0000000..86bffbe
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_assignable/incomplete_neg.cc
@@ -0,0 +1,31 @@
+// { 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_assignable<X, int>(); // { dg-error "required from here" }
+ std::is_nothrow_assignable<int, X>(); // { dg-error "required from here" }
+ std::is_nothrow_assignable<X, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc
new file mode 100644
index 0000000..c944d30
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc
@@ -0,0 +1,32 @@
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+//
+// 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_convertible<X, int>(); // { dg-error "required from here" }
+ std::is_nothrow_convertible<int, X>(); // { dg-error "required from here" }
+ std::is_nothrow_convertible<X, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc
new file mode 100644
index 0000000..5ddb6b5
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/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_nothrow_swappable<X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc
new file mode 100644
index 0000000..5a0bcbb
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc
@@ -0,0 +1,31 @@
+// { 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_nothrow_swappable_with<X, int>(); // { dg-error "required from here" }
+ std::is_nothrow_swappable_with<int, X>(); // { dg-error "required from here" }
+ std::is_nothrow_swappable_with<X, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_swappable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_swappable/incomplete_neg.cc
new file mode 100644
index 0000000..c7ec399
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_swappable/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_swappable<X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_swappable_with/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_swappable_with/incomplete_neg.cc
new file mode 100644
index 0000000..5fbd3e0
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_swappable_with/incomplete_neg.cc
@@ -0,0 +1,31 @@
+// { 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_swappable_with<X, int>(); // { dg-error "required from here" }
+ std::is_swappable_with<int, X>(); // { dg-error "required from here" }
+ std::is_swappable_with<X, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_trivially_assignable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_trivially_assignable/incomplete_neg.cc
new file mode 100644
index 0000000..a93285c
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_trivially_assignable/incomplete_neg.cc
@@ -0,0 +1,33 @@
+// { 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/>.
+
+// { dg-error "must be a complete class" "" { target *-*-* } 0 }
+
+#include <type_traits>
+
+class X;
+
+void test01()
+{
+ std::is_trivially_assignable<X, int>(); // { dg-error "required from here" }
+ std::is_trivially_assignable<int, X>(); // { dg-error "required from here" }
+ std::is_trivially_assignable<X, X>(); // { dg-error "required from here" }
+}
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2019-06-20 17:49 ` Antony Polukhin
@ 2019-06-20 17:57 ` Ville Voutilainen
2019-06-20 18:56 ` Antony Polukhin
0 siblings, 1 reply; 20+ messages in thread
From: Ville Voutilainen @ 2019-06-20 17:57 UTC (permalink / raw)
To: Antony Polukhin; +Cc: Jonathan Wakely, libstdc++, gcc-patches List
On Thu, 20 Jun 2019 at 20:49, Antony Polukhin <antoshkka@gmail.com> wrote:
>
> чт, 6 июн. 2019 г. в 15:19, Jonathan Wakely <jwakely@redhat.com>:
> > I'm removing some of these assertions again, because they are either
> > reundant or wrong.
>
> Thanks for cleaning up!
>
>
> In attachment there is an additional patch for type traits hardening.
>
> Things that still remain unasserted are type traits with variadic
> template arguments. I have to came up with a proper solution for
> providing a useful and lightweight diagnostics.
I see a
public __bool_constant<__is_trivially_assignable(_Tp, _Up)>
in this patch, followed by a trait-body that static_asserts. In such
cases, I think we want
to
a) be really careful about duplicating compiler diagnostics with library ones
b) look at the compiler diagnostics, and if they are lacking, improve them.
...because that's what Jonathan's cleanup was really about.
In the test modifications of __is_trivially_assignable, this looks bloody
suspicious:
+// { dg-prune-output "invalid use of incomplete type" }
+// { dg-prune-output "must be a complete" }
No. Don't merge. We are not replacing diagnostics A with diagnostics
B, we are ignoring existing
diagnostics and adding more. Which is exactly what Jonathan's cleanup avoided.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2019-06-20 17:57 ` Ville Voutilainen
@ 2019-06-20 18:56 ` Antony Polukhin
2020-08-12 8:19 ` Antony Polukhin
0 siblings, 1 reply; 20+ messages in thread
From: Antony Polukhin @ 2019-06-20 18:56 UTC (permalink / raw)
To: Ville Voutilainen; +Cc: Jonathan Wakely, libstdc++, gcc-patches List
чт, 20 июн. 2019 г. в 20:57, Ville Voutilainen <ville.voutilainen@gmail.com>:
>
> On Thu, 20 Jun 2019 at 20:49, Antony Polukhin <antoshkka@gmail.com> wrote:
> >
> > чт, 6 июн. 2019 г. в 15:19, Jonathan Wakely <jwakely@redhat.com>:
> > > I'm removing some of these assertions again, because they are either
> > > reundant or wrong.
> >
> > Thanks for cleaning up!
> >
> >
> > In attachment there is an additional patch for type traits hardening.
> >
> > Things that still remain unasserted are type traits with variadic
> > template arguments. I have to came up with a proper solution for
> > providing a useful and lightweight diagnostics.
>
> I see a
> public __bool_constant<__is_trivially_assignable(_Tp, _Up)>
> in this patch, followed by a trait-body that static_asserts. In such
> cases, I think we want
> to
> a) be really careful about duplicating compiler diagnostics with library ones
> b) look at the compiler diagnostics, and if they are lacking, improve them.
>
> ...because that's what Jonathan's cleanup was really about.
> In the test modifications of __is_trivially_assignable, this looks bloody
> suspicious:
>
> +// { dg-prune-output "invalid use of incomplete type" }
> +// { dg-prune-output "must be a complete" }
>
> No. Don't merge. We are not replacing diagnostics A with diagnostics
> B, we are ignoring existing
> diagnostics and adding more. Which is exactly what Jonathan's cleanup avoided.
Thanks for the review and clarifications. I'll fix the patch.
--
Best regards,
Antony Polukhin
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2019-06-20 18:56 ` Antony Polukhin
@ 2020-08-12 8:19 ` Antony Polukhin
2020-08-19 11:29 ` Jonathan Wakely
0 siblings, 1 reply; 20+ messages in thread
From: Antony Polukhin @ 2020-08-12 8:19 UTC (permalink / raw)
To: Ville Voutilainen; +Cc: Jonathan Wakely, libstdc++, gcc-patches List
[-- Attachment #1: Type: text/plain, Size: 897 bytes --]
Fixed patch for type traits hardening
Changelog
2020-08-12 Antony Polukhin <antoshkka@gmail.com>
PR libstdc/71579
* include/std/type_traits (invoke_result, is_nothrow_invocable_r)
Add static_asserts to make sure that the argument of the type
trait is not misused with incomplete types.
(is_swappable_with, is_nothrow_swappable_with): Add static_asserts
to make sure that the first and second arguments of the type trait
are not misused with incomplete types.
* testsuite/20_util/invoke_result/incomplete_neg.cc: New test.
* testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc: New test.
* testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc: New test.
* testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc: New
test.
* testsuite/20_util/is_swappable_with/incomplete_neg.cc: New test.
--
Best regards,
Antony Polukhin
[-- Attachment #2: type_traits_hardening2.5.txt --]
[-- Type: text/plain, Size: 9428 bytes --]
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 426febc..62f1190 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2811,13 +2811,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Up>
struct is_swappable_with
: public __is_swappable_with_impl<_Tp, _Up>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "first template argument must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Up>{}),
+ "second template argument must be a complete class or an unbounded array");
+ };
/// is_nothrow_swappable_with
template<typename _Tp, typename _Up>
struct is_nothrow_swappable_with
: public __is_nothrow_swappable_with_impl<_Tp, _Up>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+ "first template argument must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Up>{}),
+ "second template argument must be a complete class or an unbounded array");
+ };
#if __cplusplus >= 201402L
/// is_swappable_with_v
@@ -2952,7 +2962,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Functor, typename... _ArgTypes>
struct invoke_result
: public __invoke_result<_Functor, _ArgTypes...>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Functor>{}),
+ "_Functor must be a complete class or an unbounded array");
+ };
/// std::invoke_result_t
template<typename _Fn, typename... _Args>
@@ -3001,7 +3014,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct is_nothrow_invocable_r
: __and_<__is_nt_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>,
__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");
+ };
/// std::is_invocable_v
template<typename _Fn, typename... _Args>
diff --git a/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_neg.cc
new file mode 100644
index 0000000..da58a8b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_neg.cc
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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::invoke_result<X, int>(); // { dg-error "required from here" }
+ std::invoke_result<X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc
new file mode 100644
index 0000000..ad16809
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc
@@ -0,0 +1,33 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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_invocable<X>(); // { dg-error "required from here" }
+ std::is_nothrow_invocable<X, short>(); // { dg-error "required from here" }
+
+ std::is_nothrow_invocable_r<int, X>(); // { dg-error "required from here" }
+ std::is_nothrow_invocable_r<int, X, short>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc
new file mode 100644
index 0000000..4a6261d
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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_swappable<X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc
new file mode 100644
index 0000000..2fb19de
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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_swappable_with<X, int>(); // { dg-error "required from here" }
+ std::is_nothrow_swappable_with<int, X>(); // { dg-error "required from here" }
+ std::is_nothrow_swappable_with<X, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_swappable_with/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_swappable_with/incomplete_neg.cc
new file mode 100644
index 0000000..dafa4f7
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_swappable_with/incomplete_neg.cc
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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_swappable_with<X, int>(); // { dg-error "required from here" }
+ std::is_swappable_with<int, X>(); // { dg-error "required from here" }
+ std::is_swappable_with<X, X>(); // { dg-error "required from here" }
+}
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2020-08-12 8:19 ` Antony Polukhin
@ 2020-08-19 11:29 ` Jonathan Wakely
2020-08-19 16:44 ` Antony Polukhin
2020-08-20 15:31 ` Antony Polukhin
0 siblings, 2 replies; 20+ messages in thread
From: Jonathan Wakely @ 2020-08-19 11:29 UTC (permalink / raw)
To: Antony Polukhin; +Cc: Ville Voutilainen, libstdc++, gcc-patches List
On 12/08/20 11:19 +0300, Antony Polukhin via Libstdc++ wrote:
>Fixed patch for type traits hardening
>
>Changelog
>
>2020-08-12 Antony Polukhin <antoshkka@gmail.com>
>
> PR libstdc/71579
> * include/std/type_traits (invoke_result, is_nothrow_invocable_r)
> Add static_asserts to make sure that the argument of the type
> trait is not misused with incomplete types.
> (is_swappable_with, is_nothrow_swappable_with): Add static_asserts
> to make sure that the first and second arguments of the type trait
> are not misused with incomplete types.
> * testsuite/20_util/invoke_result/incomplete_neg.cc: New test.
> * testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc: New test.
> * testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc: New test.
> * testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc: New
> test.
> * testsuite/20_util/is_swappable_with/incomplete_neg.cc: New test.
Thanks, pushed to master.
Do we also want to check
(std::__is_complete_or_unbounded(__type_identity<_ArgTypes>{}) && ...)
for invoke_result and the is_invocable traits?
We can use a fold expression there, because those traits are not
defined before C++17.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2020-08-19 11:29 ` Jonathan Wakely
@ 2020-08-19 16:44 ` Antony Polukhin
2020-08-20 15:31 ` Antony Polukhin
1 sibling, 0 replies; 20+ messages in thread
From: Antony Polukhin @ 2020-08-19 16:44 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: Ville Voutilainen, libstdc++, gcc-patches List
ср, 19 авг. 2020 г. в 14:29, Jonathan Wakely <jwakely@redhat.com>:
<...>
> Do we also want to check
> (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>{}) && ...)
> for invoke_result and the is_invocable traits?
>
> We can use a fold expression there, because those traits are not
> defined before C++17.
Good idea. I'll try.
--
Best regards,
Antony Polukhin
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2020-08-19 11:29 ` Jonathan Wakely
2020-08-19 16:44 ` Antony Polukhin
@ 2020-08-20 15:31 ` Antony Polukhin
2020-09-24 7:15 ` Antony Polukhin
2020-09-24 17:53 ` Jonathan Wakely
1 sibling, 2 replies; 20+ messages in thread
From: Antony Polukhin @ 2020-08-20 15:31 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: Ville Voutilainen, libstdc++, gcc-patches List
[-- Attachment #1: Type: text/plain, Size: 1048 bytes --]
ср, 19 авг. 2020 г. в 14:29, Jonathan Wakely <jwakely@redhat.com>:
<...>
> Do we also want to check
> (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>{}) && ...)
> for invoke_result and the is_invocable traits?
Done.
Changelog:
2020-08-20 Antony Polukhin <antoshkka@gmail.com>
PR libstdc/71579
* include/std/type_traits (invoke_result, is_invocable, is_invocable_r)
(is_nothrow_invocable, is_nothrow_invocable_r): Add static_asserts
to make sure that the arguments of the type traits are not misused
with incomplete types.`
* testsuite/20_util/invoke_result/incomplete_args_neg.cc: New test.
* testsuite/20_util/is_invocable/incomplete_args_neg.cc: New test.
* testsuite/20_util/is_invocable/incomplete_neg.cc: New test.
* testsuite/20_util/is_nothrow_invocable/incomplete_args_neg.cc: New test.
* testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc: Check for
error on incomplete response type usage in trait.
--
Best regards,
Antony Polukhin
[-- Attachment #2: type_traits_hardening3.txt --]
[-- Type: text/plain, Size: 15059 bytes --]
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 6ced781..bf2260a 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2965,6 +2965,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
static_assert(std::__is_complete_or_unbounded(__type_identity<_Functor>{}),
"_Functor must be a complete class or an unbounded array");
+ static_assert((std::__is_complete_or_unbounded(
+ __type_identity<_ArgTypes>{}) && ...),
+ "Argument types must be a complete class or an unbounded array");
};
/// std::invoke_result_t
@@ -2978,6 +2981,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
"_Fn must be a complete class or an unbounded array");
+ static_assert((std::__is_complete_or_unbounded(
+ __type_identity<_ArgTypes>{}) && ...),
+ "Argument types must be a complete class or an unbounded array");
};
/// std::is_invocable_r
@@ -2987,6 +2993,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
"_Fn must be a complete class or an unbounded array");
+ static_assert((std::__is_complete_or_unbounded(
+ __type_identity<_ArgTypes>{}) && ...),
+ "Argument types must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Ret>{}),
+ "_Ret must be a complete class or an unbounded array");
};
/// std::is_nothrow_invocable
@@ -2997,6 +3008,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
"_Fn must be a complete class or an unbounded array");
+ static_assert((std::__is_complete_or_unbounded(
+ __type_identity<_ArgTypes>{}) && ...),
+ "Argument types must be a complete class or an unbounded array");
};
template<typename _Result, typename _Ret, typename = void>
@@ -3017,6 +3031,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
"_Fn must be a complete class or an unbounded array");
+ static_assert((std::__is_complete_or_unbounded(
+ __type_identity<_ArgTypes>{}) && ...),
+ "Argument types must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Ret>{}),
+ "_Ret must be a complete class or an unbounded array");
};
/// std::is_invocable_v
diff --git a/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_args_neg.cc b/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_args_neg.cc
new file mode 100644
index 0000000..a35ff4c
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_args_neg.cc
@@ -0,0 +1,47 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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::invoke_result<int(X), X>(); // { dg-error "required from here" }
+ std::invoke_result<int(int, X), int, X>(); // { dg-error "required from here" }
+ std::invoke_result<int(int, X), X, int>(); // { dg-error "required from here" }
+
+
+ std::invoke_result<int(X&), X&>(); // { dg-bogus "required from here" }
+ std::invoke_result<int(int, X&), int, X&>(); // { dg-bogus "required from here" }
+
+ std::invoke_result<int(X&&), X&&>(); // { dg-bogus "required from here" }
+ std::invoke_result<int(int, X&&), int, X&&>(); // { dg-bogus "required from here" }
+
+ std::invoke_result<int(const X&&), const X&&>(); // { dg-bogus "required from here" }
+ std::invoke_result<int(int, const X&&), int, const X&&>(); // { dg-bogus "required from here" }
+
+ std::invoke_result<int(const X&), const X&>(); // { dg-bogus "required from here" }
+ std::invoke_result<int(int, const X&), int, const X&>(); // { dg-bogus "required from here" }
+
+ std::invoke_result<int(const X&), X&>(); // { dg-bogus "required from here" }
+ std::invoke_result<int(int, const X&), int, X&>(); // { dg-bogus "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
new file mode 100644
index 0000000..a5ce49a
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
@@ -0,0 +1,70 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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_invocable<int(X), X>(); // { dg-error "required from here" }
+ std::is_invocable<int(int, X), int, X>(); // { dg-error "required from here" }
+ std::is_invocable<int(int, X), X, int>(); // { dg-error "required from here" }
+
+
+ std::is_invocable<int(X&), X&>(); // { dg-bogus "required from here" }
+ std::is_invocable<int(int, X&), int, X&>(); // { dg-bogus "required from here" }
+
+ std::is_invocable<int(X&&), X&&>(); // { dg-bogus "required from here" }
+ std::is_invocable<int(int, X&&), int, X&&>(); // { dg-bogus "required from here" }
+
+ std::is_invocable<int(const X&&), const X&&>(); // { dg-bogus "required from here" }
+ std::is_invocable<int(int, const X&&), int, const X&&>(); // { dg-bogus "required from here" }
+
+ std::is_invocable<int(const X&), const X&>(); // { dg-bogus "required from here" }
+ std::is_invocable<int(int, const X&), int, const X&>(); // { dg-bogus "required from here" }
+
+ std::is_invocable<int(const X&), X&>(); // { dg-bogus "required from here" }
+ std::is_invocable<int(int, const X&), int, X&>(); // { dg-bogus "required from here" }
+}
+
+void test02()
+{
+ std::is_invocable_r<int, int(X), X>(); // { dg-error "required from here" }
+ std::is_invocable_r<int, int(int, X), int, X>(); // { dg-error "required from here" }
+ std::is_invocable_r<int, int(int, X), X, int>(); // { dg-error "required from here" }
+
+
+ std::is_invocable_r<int, int(X&), X&>(); // { dg-bogus "required from here" }
+ std::is_invocable_r<int, int(int, X&), int, X&>(); // { dg-bogus "required from here" }
+
+ std::is_invocable_r<int, int(X&&), X&&>(); // { dg-bogus "required from here" }
+ std::is_invocable_r<int, int(int, X&&), int, X&&>(); // { dg-bogus "required from here" }
+
+ std::is_invocable_r<int, int(const X&&), const X&&>(); // { dg-bogus "required from here" }
+ std::is_invocable_r<int, int(int, const X&&), int, const X&&>(); // { dg-bogus "required from here" }
+
+ std::is_invocable_r<int, int(const X&), const X&>(); // { dg-bogus "required from here" }
+ std::is_invocable_r<int, int(int, const X&), int, const X&>(); // { dg-bogus "required from here" }
+
+ std::is_invocable_r<int, int(const X&), X&>(); // { dg-bogus "required from here" }
+ std::is_invocable_r<int, int(int, const X&), int, X&>(); // { dg-bogus "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
new file mode 100644
index 0000000..3041554
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
@@ -0,0 +1,39 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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_invocable<X, int>(); // { dg-error "required from here" }
+ std::is_invocable<X>(); // { dg-error "required from here" }
+
+ std::is_invocable_r<int, X, int>(); // { dg-error "required from here" }
+ std::is_invocable_r<int, X>(); // { dg-error "required from here" }
+
+ std::is_invocable_r<X, X()>(); // { dg-error "required from here" }
+ std::is_invocable_r<X, X(int), int>(); // { dg-error "required from here" }
+ std::is_invocable_r<X, X(int, int), int, int>(); // { dg-error "required from here" }
+
+ std::is_invocable_r<X, X(), int, int>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_args_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_args_neg.cc
new file mode 100644
index 0000000..c60e73b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_args_neg.cc
@@ -0,0 +1,70 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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_invocable<int(X), X>(); // { dg-error "required from here" }
+ std::is_nothrow_invocable<int(int, X), int, X>(); // { dg-error "required from here" }
+ std::is_nothrow_invocable<int(int, X), X, int>(); // { dg-error "required from here" }
+
+
+ std::is_nothrow_invocable<int(X&), X&>(); // { dg-bogus "required from here" }
+ std::is_nothrow_invocable<int(int, X&), int, X&>(); // { dg-bogus "required from here" }
+
+ std::is_nothrow_invocable<int(X&&), X&&>(); // { dg-bogus "required from here" }
+ std::is_nothrow_invocable<int(int, X&&), int, X&&>(); // { dg-bogus "required from here" }
+
+ std::is_nothrow_invocable<int(const X&&), const X&&>(); // { dg-bogus "required from here" }
+ std::is_nothrow_invocable<int(int, const X&&), int, const X&&>(); // { dg-bogus "required from here" }
+
+ std::is_nothrow_invocable<int(const X&), const X&>(); // { dg-bogus "required from here" }
+ std::is_nothrow_invocable<int(int, const X&), int, const X&>(); // { dg-bogus "required from here" }
+
+ std::is_nothrow_invocable<int(const X&), X&>(); // { dg-bogus "required from here" }
+ std::is_nothrow_invocable<int(int, const X&), int, X&>(); // { dg-bogus "required from here" }
+}
+
+void test02()
+{
+ std::is_nothrow_invocable_r<int, int(X), X>(); // { dg-error "required from here" }
+ std::is_nothrow_invocable_r<int, int(int, X), int, X>(); // { dg-error "required from here" }
+ std::is_nothrow_invocable_r<int, int(int, X), X, int>(); // { dg-error "required from here" }
+
+
+ std::is_nothrow_invocable_r<int, int(X&), X&>(); // { dg-bogus "required from here" }
+ std::is_nothrow_invocable_r<int, int(int, X&), int, X&>(); // { dg-bogus "required from here" }
+
+ std::is_nothrow_invocable_r<int, int(X&&), X&&>(); // { dg-bogus "required from here" }
+ std::is_nothrow_invocable_r<int, int(int, X&&), int, X&&>(); // { dg-bogus "required from here" }
+
+ std::is_nothrow_invocable_r<int, int(const X&&), const X&&>(); // { dg-bogus "required from here" }
+ std::is_nothrow_invocable_r<int, int(int, const X&&), int, const X&&>(); // { dg-bogus "required from here" }
+
+ std::is_nothrow_invocable_r<int, int(const X&), const X&>(); // { dg-bogus "required from here" }
+ std::is_nothrow_invocable_r<int, int(int, const X&), int, const X&>(); // { dg-bogus "required from here" }
+
+ std::is_nothrow_invocable_r<int, int(const X&), X&>(); // { dg-bogus "required from here" }
+ std::is_nothrow_invocable_r<int, int(int, const X&), int, X&>(); // { dg-bogus "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc
index ad16809..ef87171 100644
--- a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc
@@ -30,4 +30,10 @@ void test01()
std::is_nothrow_invocable_r<int, X>(); // { dg-error "required from here" }
std::is_nothrow_invocable_r<int, X, short>(); // { dg-error "required from here" }
+
+ std::is_nothrow_invocable_r<X, X()>(); // { dg-error "required from here" }
+ std::is_nothrow_invocable_r<X, X(int), int>(); // { dg-error "required from here" }
+ std::is_nothrow_invocable_r<X, X(int, int), int, int>(); // { dg-error "required from here" }
+
+ std::is_nothrow_invocable_r<X, X(), int, int>(); // { dg-error "required from here" }
}
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2020-08-20 15:31 ` Antony Polukhin
@ 2020-09-24 7:15 ` Antony Polukhin
2020-09-24 9:29 ` Jonathan Wakely
2020-09-24 17:53 ` Jonathan Wakely
1 sibling, 1 reply; 20+ messages in thread
From: Antony Polukhin @ 2020-09-24 7:15 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: Ville Voutilainen, libstdc++, gcc-patches List
Looks like the last patch was not applied. Do I have to change something in
it?
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2020-09-24 7:15 ` Antony Polukhin
@ 2020-09-24 9:29 ` Jonathan Wakely
0 siblings, 0 replies; 20+ messages in thread
From: Jonathan Wakely @ 2020-09-24 9:29 UTC (permalink / raw)
To: Antony Polukhin; +Cc: gcc-patches List, libstdc++
On 24/09/20 10:15 +0300, Antony Polukhin via Libstdc++ wrote:
>Looks like the last patch was not applied. Do I have to change something in
>it?
No, it just hasn't been reviewed yet.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2020-08-20 15:31 ` Antony Polukhin
2020-09-24 7:15 ` Antony Polukhin
@ 2020-09-24 17:53 ` Jonathan Wakely
2020-11-12 18:55 ` Antony Polukhin
1 sibling, 1 reply; 20+ messages in thread
From: Jonathan Wakely @ 2020-09-24 17:53 UTC (permalink / raw)
To: Antony Polukhin; +Cc: gcc-patches List, libstdc++
On 20/08/20 18:31 +0300, Antony Polukhin via Libstdc++ wrote:
>ср, 19 авг. 2020 г. в 14:29, Jonathan Wakely <jwakely@redhat.com>:
><...>
>> Do we also want to check
>> (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>{}) && ...)
>> for invoke_result and the is_invocable traits?
>
>Done.
>
>Changelog:
>
>2020-08-20 Antony Polukhin <antoshkka@gmail.com>
>
> PR libstdc/71579
> * include/std/type_traits (invoke_result, is_invocable, is_invocable_r)
> (is_nothrow_invocable, is_nothrow_invocable_r): Add static_asserts
> to make sure that the arguments of the type traits are not misused
> with incomplete types.`
> * testsuite/20_util/invoke_result/incomplete_args_neg.cc: New test.
> * testsuite/20_util/is_invocable/incomplete_args_neg.cc: New test.
> * testsuite/20_util/is_invocable/incomplete_neg.cc: New test.
> * testsuite/20_util/is_nothrow_invocable/incomplete_args_neg.cc: New test.
> * testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc: Check for
> error on incomplete response type usage in trait.
Committed with some tweaks to the static assert messages to say:
"each argument type must be a complete class or an unbounded array"
Thanks!
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2020-09-24 17:53 ` Jonathan Wakely
@ 2020-11-12 18:55 ` Antony Polukhin
2021-01-08 17:28 ` Antony Polukhin
0 siblings, 1 reply; 20+ messages in thread
From: Antony Polukhin @ 2020-11-12 18:55 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: gcc-patches List, libstdc++
[-- Attachment #1: Type: text/plain, Size: 1464 bytes --]
Final bits for libstdc/71579
std::common_type assertions attempt to give a proper 'required from
here' hint for user code, do not bring many changes to the
implementation and check all the template parameters for completeness.
In some cases the type could be checked for completeness more than
once. This seems to be unsolvable due to the fact that
std::common_type could be specialized by the user, so we have to call
std::common_type recursively, potentially repeating the check for the
first type.
std::common_reference assertions make sure that we detect incomplete
types even if the user specialized the std::basic_common_reference.
Changelog:
2020-11-12 Antony Polukhin <antoshkka@gmail.com>
PR libstdc/71579
* include/std/type_traits (is_convertible, is_nothrow_convertible)
(common_type, common_reference): Add static_asserts
to make sure that the arguments of the type traits are not misused
with incomplete types.
* testsuite/20_util/common_reference/incomplete_basic_common_neg.cc:
New test.
* testsuite/20_util/common_reference/incomplete_neg.cc: New test.
* testsuite/20_util/common_type/incomplete_neg.cc: New test.
* testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc: Remove
SFINAE tests on incomplete types.
* testsuite/20_util/is_convertible/incomplete_neg.cc: New test.
* testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc: New test.
--
Best regards,
Antony Polukhin
[-- Attachment #2: type_traits_hardening-4.txt --]
[-- Type: text/plain, Size: 19045 bytes --]
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 34e068b..00fa7f5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1406,12 +1406,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _From, typename _To>
struct is_convertible
: public __is_convertible_helper<_From, _To>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_From>{}),
+ "first template argument must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_To>{}),
+ "second template argument must be a complete class or an unbounded array");
+ };
// helper trait for unique_ptr<T[]>, shared_ptr<T[]>, and span<T, N>
template<typename _ToElementType, typename _FromElementType>
using __is_array_convertible
- = is_convertible<_FromElementType(*)[], _ToElementType(*)[]>;
+ = typename __is_convertible_helper<
+ _FromElementType(*)[], _ToElementType(*)[]>::type;
template<typename _From, typename _To,
bool = __or_<is_void<_From>, is_function<_To>,
@@ -1454,7 +1460,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _From, typename _To>
struct is_nothrow_convertible
: public __is_nt_convertible_helper<_From, _To>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_From>{}),
+ "first template argument must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_To>{}),
+ "second template argument must be a complete class or an unbounded array");
+ };
/// is_nothrow_convertible_v
template<typename _From, typename _To>
@@ -2239,7 +2250,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp1, typename _Tp2>
struct common_type<_Tp1, _Tp2>
: public __common_type_impl<_Tp1, _Tp2>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp1>{}),
+ "each argument type must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp2>{}),
+ "each argument type must be a complete class or an unbounded array");
+ };
template<typename...>
struct __common_type_pack
@@ -2253,7 +2269,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct common_type<_Tp1, _Tp2, _Rp...>
: public __common_type_fold<common_type<_Tp1, _Tp2>,
__common_type_pack<_Rp...>>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp1>{}),
+ "first argument type must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp2>{}),
+ "second argument type must be a complete class or an unbounded array");
+#ifdef __cpp_fold_expressions
+ static_assert((std::__is_complete_or_unbounded(
+ __type_identity<_Rp>{}) && ...),
+ "each argument type must be a complete class or an unbounded array");
+#endif
+ };
// Let C denote the same type, if any, as common_type_t<T1, T2>.
// If there is such a type C, type shall denote the same type, if any,
@@ -3315,9 +3341,10 @@ template <typename _From, typename _To>
// If A and B are both rvalue reference types, ...
template<typename _Xp, typename _Yp>
- struct __common_ref_impl<_Xp&&, _Yp&&,
- _Require<is_convertible<_Xp&&, __common_ref_C<_Xp, _Yp>>,
- is_convertible<_Yp&&, __common_ref_C<_Xp, _Yp>>>>
+ struct __common_ref_impl<_Xp&&, _Yp&&, _Require<
+ typename __is_convertible_helper<_Xp&&, __common_ref_C<_Xp, _Yp>>::type,
+ typename __is_convertible_helper<_Yp&&, __common_ref_C<_Xp, _Yp>>::type
+ >>
{ using type = __common_ref_C<_Xp, _Yp>; };
// let D be COMMON-REF(const X&, Y&)
@@ -3326,8 +3353,9 @@ template <typename _From, typename _To>
// If A is an rvalue reference and B is an lvalue reference, ...
template<typename _Xp, typename _Yp>
- struct __common_ref_impl<_Xp&&, _Yp&,
- _Require<is_convertible<_Xp&&, __common_ref_D<_Xp, _Yp>>>>
+ struct __common_ref_impl<_Xp&&, _Yp&, _Require<
+ typename __is_convertible_helper<_Xp&&, __common_ref_D<_Xp, _Yp>>::type
+ >>
{ using type = __common_ref_D<_Xp, _Yp>; };
// If A is an lvalue reference and B is an rvalue reference, ...
@@ -3374,7 +3402,12 @@ template <typename _From, typename _To>
// If sizeof...(T) is one ...
template<typename _Tp0>
struct common_reference<_Tp0>
- { using type = _Tp0; };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp0>{}),
+ "each argument type must be a complete class or an unbounded array");
+
+ using type = _Tp0;
+ };
template<typename _Tp1, typename _Tp2, int _Bullet = 1, typename = void>
struct __common_reference_impl
@@ -3385,7 +3418,12 @@ template <typename _From, typename _To>
template<typename _Tp1, typename _Tp2>
struct common_reference<_Tp1, _Tp2>
: __common_reference_impl<_Tp1, _Tp2>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp1>{}),
+ "each argument type must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp2>{}),
+ "each argument type must be a complete class or an unbounded array");
+ };
// If T1 and T2 are reference types and COMMON-REF(T1, T2) is well-formed, ...
template<typename _Tp1, typename _Tp2>
diff --git a/libstdc++-v3/testsuite/20_util/common_reference/incomplete_basic_common_neg.cc b/libstdc++-v3/testsuite/20_util/common_reference/incomplete_basic_common_neg.cc
new file mode 100644
index 0000000..9724ad0
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/common_reference/incomplete_basic_common_neg.cc
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++20 } }
+
+// Copyright (C) 2020 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;
+
+template <>
+struct std::basic_common_reference<X, X> {
+ using type = int;
+};
+
+void test01()
+{
+ std::common_reference<X>(); // { dg-error "required from here" }
+ std::common_reference<X, X>(); // { dg-error "required from here" }
+ std::common_reference<X, X, X>(); // { dg-error "required from here" }
+ std::common_reference<X, X, X, X>(); // { dg-error "required from here" }
+ std::common_reference<X, X, X, X, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/common_reference/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/common_reference/incomplete_neg.cc
new file mode 100644
index 0000000..c151d4a
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/common_reference/incomplete_neg.cc
@@ -0,0 +1,58 @@
+// { dg-do compile { target c++20 } }
+
+// Copyright (C) 2020 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;
+class Y {};
+
+void test01()
+{
+ std::common_reference<X>(); // { dg-error "required from here" }
+ std::common_reference<X, int>(); // { dg-error "required from here" }
+ std::common_reference<X, int, int>(); // { dg-error "required from here" }
+ std::common_reference<X, int, int, int>(); // { dg-error "required from here" }
+ std::common_reference<X, int, int, int, int>(); // { dg-error "required from here" }
+
+ std::common_reference<int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, X, int>(); // { dg-error "required from here" }
+ std::common_reference<int, X, int, int>(); // { dg-error "required from here" }
+ std::common_reference<int, X, int, int, int>(); // { dg-error "required from here" }
+
+ std::common_reference<int, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, int, X, int>(); // { dg-error "required from here" }
+ std::common_reference<int, int, X, int, int>(); // { dg-error "required from here" }
+
+ std::common_reference<int, int, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, int, int, X, int>(); // { dg-error "required from here" }
+
+ std::common_reference<int, int, int, int, X>(); // { dg-error "required from here" }
+
+ std::common_reference<X, int, int, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, X, int, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, int, X, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, int, int, X, X>(); // { dg-error "required from here" }
+
+ std::common_reference<Y, int, int, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, Y, int, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, int, Y, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, int, int, Y, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/common_type/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/common_type/incomplete_neg.cc
new file mode 100644
index 0000000..6c2641d
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/common_type/incomplete_neg.cc
@@ -0,0 +1,59 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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;
+class Y {};
+
+// Some of the following asserts require __cpp_fold_expressions to trigger
+void test01()
+{
+ std::common_type<X>(); // { dg-error "required from here" }
+ std::common_type<X, int>(); // { dg-error "required from here" }
+ std::common_type<X, int, int>(); // { dg-error "required from here" }
+ std::common_type<X, int, int, int>(); // { dg-error "required from here" }
+ std::common_type<X, int, int, int, int>(); // { dg-error "required from here" }
+
+ std::common_type<int, X>(); // { dg-error "required from here" }
+ std::common_type<int, X, int>(); // { dg-error "required from here" }
+ std::common_type<int, X, int, int>(); // { dg-error "required from here" }
+ std::common_type<int, X, int, int, int>(); // { dg-error "required from here" }
+
+ std::common_type<int, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, int, X, int>(); // { dg-error "required from here" }
+ std::common_type<int, int, X, int, int>(); // { dg-error "required from here" }
+
+ std::common_type<int, int, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, int, int, X, int>(); // { dg-error "required from here" }
+
+ std::common_type<int, int, int, int, X>(); // { dg-error "required from here" }
+
+ std::common_type<X, int, int, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, X, int, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, int, X, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, int, int, X, X>(); // { dg-error "required from here" }
+
+ std::common_type<Y, int, int, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, Y, int, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, int, Y, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, int, int, Y, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc b/libstdc++-v3/testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc
index 04eef50..a52f186 100644
--- a/libstdc++-v3/testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc
+++ b/libstdc++-v3/testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc
@@ -89,7 +89,7 @@ enum class ScEn;
enum UnscEn : int;
-struct Ukn;
+
union U
{
@@ -240,7 +240,7 @@ static_assert(is_type<std::common_type<decltype(nullptr), int (B::*)() const>,
static_assert(is_type<std::common_type<decltype(nullptr), const int B::*>,
const int B::*>(), "");
static_assert(is_type<std::common_type<Abstract&, Abstract&>, Abstract>(), "");
-static_assert(is_type<std::common_type<Ukn&, Ukn&>, Ukn>(), "");
+
static_assert(is_type<std::common_type<ImplicitTo<B&>, B&>, B>(), "");
static_assert(is_type<std::common_type<ImplicitTo<B&>&, B&&>, B>(), "");
static_assert(is_type<std::common_type<UConv1, const Abstract*&>,
@@ -254,11 +254,6 @@ static_assert(is_type<std::common_type<const Abstract&&,
const Abstract&&>, Abstract>(), "");
static_assert(is_type<std::common_type<volatile Abstract&&,
volatile Abstract&&>, Abstract>(), "");
-static_assert(is_type<std::common_type<Ukn&&, Ukn&&>, Ukn>(), "");
-static_assert(is_type<std::common_type<const Ukn&&, const Ukn&&>,
- Ukn>(), "");
-static_assert(is_type<std::common_type<volatile Ukn&&, volatile Ukn&&>,
- Ukn>(), "");
static_assert(is_type<std::common_type<X1, X2>, RX12>(), "");
static_assert(is_type<std::common_type<const X1, X2>, RX12>(), "");
@@ -280,13 +275,13 @@ static_assert(!has_type<std::common_type<U, U2>>(), "");
static_assert(!has_type<std::common_type<PrivateImplicitTo<int>, int>>(), "");
static_assert(!has_type<std::common_type<const PrivateImplicitTo<int>,
int>>(), "");
-static_assert(!has_type<std::common_type<int, Ukn>>(), "");
+
static_assert(!has_type<std::common_type<int, Abstract>>(), "");
-static_assert(!has_type<std::common_type<Ukn, Abstract>>(), "");
+
static_assert(!has_type<std::common_type<int, void>>(), "");
static_assert(!has_type<std::common_type<int, const volatile void>>(), "");
static_assert(!has_type<std::common_type<Abstract, void>>(), "");
-static_assert(!has_type<std::common_type<Ukn, void>>(), "");
+
static_assert(!has_type<std::common_type<int[4], void>>(), "");
static_assert(!has_type<std::common_type<ScEn, void>>(), "");
static_assert(!has_type<std::common_type<UnscEn, void>>(), "");
diff --git a/libstdc++-v3/testsuite/20_util/is_convertible/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_convertible/incomplete_neg.cc
new file mode 100644
index 0000000..7fe7f8b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_convertible/incomplete_neg.cc
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2020 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_convertible<X, int>(); // { dg-error "required from here" }
+ std::is_convertible<int, X>(); // { dg-error "required from here" }
+ std::is_convertible<X, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc
new file mode 100644
index 0000000..9c1d2f4
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++20 } }
+
+// Copyright (C) 2020 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_convertible<X, int>(); // { dg-error "required from here" }
+ std::is_nothrow_convertible<int, X>(); // { dg-error "required from here" }
+ std::is_nothrow_convertible<X, X>(); // { dg-error "required from here" }
+}
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2020-11-12 18:55 ` Antony Polukhin
@ 2021-01-08 17:28 ` Antony Polukhin
2021-05-07 18:00 ` Antony Polukhin
0 siblings, 1 reply; 20+ messages in thread
From: Antony Polukhin @ 2021-01-08 17:28 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: gcc-patches List, libstdc++
On Thu, Nov 12, 2020, 21:55 Antony Polukhin <antoshkka@gmail.com> wrote:
> Final bits for libstdc/71579
>
Gentle reminder on last patch
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type
2021-01-08 17:28 ` Antony Polukhin
@ 2021-05-07 18:00 ` Antony Polukhin
0 siblings, 0 replies; 20+ messages in thread
From: Antony Polukhin @ 2021-05-07 18:00 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: gcc-patches List, libstdc++
[-- Attachment #1: Type: text/plain, Size: 1778 bytes --]
Rebased the patch on current master. Please review.
Changelog stays the same:
New std::common_type assertions attempt to give a proper 'required from
here' hint for user code, do not bring many changes to the
implementation and check all the template parameters for completeness.
In some cases the type could be checked for completeness more than
once. This seems to be unsolvable due to the fact that
std::common_type could be specialized by the user, so we have to call
std::common_type recursively, potentially repeating the check for the
first type.
std::common_reference assertions make sure that we detect incomplete
types even if the user specialized the std::basic_common_reference.
2020-11-12 Antony Polukhin <antoshkka@gmail.com>
PR libstdc/71579
* include/std/type_traits (is_convertible, is_nothrow_convertible)
(common_type, common_reference): Add static_asserts
to make sure that the arguments of the type traits are not misused
with incomplete types.
* testsuite/20_util/common_reference/incomplete_basic_common_neg.cc:
New test.
* testsuite/20_util/common_reference/incomplete_neg.cc: New test.
* testsuite/20_util/common_type/incomplete_neg.cc: New test.
* testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc: Remove
SFINAE tests on incomplete types.
* testsuite/20_util/is_convertible/incomplete_neg.cc: New test.
* testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc: New test.
пт, 8 янв. 2021 г. в 20:28, Antony Polukhin <antoshkka@gmail.com>:
>
>
> On Thu, Nov 12, 2020, 21:55 Antony Polukhin <antoshkka@gmail.com> wrote:
>>
>> Final bits for libstdc/71579
>
>
> Gentle reminder on last patch
--
Best regards,
Antony Polukhin
[-- Attachment #2: type_traits_hardening-5.txt --]
[-- Type: text/plain, Size: 19045 bytes --]
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index eaf06fc..a95d327 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1406,12 +1406,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _From, typename _To>
struct is_convertible
: public __is_convertible_helper<_From, _To>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_From>{}),
+ "first template argument must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_To>{}),
+ "second template argument must be a complete class or an unbounded array");
+ };
// helper trait for unique_ptr<T[]>, shared_ptr<T[]>, and span<T, N>
template<typename _ToElementType, typename _FromElementType>
using __is_array_convertible
- = is_convertible<_FromElementType(*)[], _ToElementType(*)[]>;
+ = typename __is_convertible_helper<
+ _FromElementType(*)[], _ToElementType(*)[]>::type;
template<typename _From, typename _To,
bool = __or_<is_void<_From>, is_function<_To>,
@@ -1454,7 +1460,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _From, typename _To>
struct is_nothrow_convertible
: public __is_nt_convertible_helper<_From, _To>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_From>{}),
+ "first template argument must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_To>{}),
+ "second template argument must be a complete class or an unbounded array");
+ };
/// is_nothrow_convertible_v
template<typename _From, typename _To>
@@ -2239,7 +2250,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp1, typename _Tp2>
struct common_type<_Tp1, _Tp2>
: public __common_type_impl<_Tp1, _Tp2>::type
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp1>{}),
+ "each argument type must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp2>{}),
+ "each argument type must be a complete class or an unbounded array");
+ };
template<typename...>
struct __common_type_pack
@@ -2253,7 +2269,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct common_type<_Tp1, _Tp2, _Rp...>
: public __common_type_fold<common_type<_Tp1, _Tp2>,
__common_type_pack<_Rp...>>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp1>{}),
+ "first argument type must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp2>{}),
+ "second argument type must be a complete class or an unbounded array");
+#ifdef __cpp_fold_expressions
+ static_assert((std::__is_complete_or_unbounded(
+ __type_identity<_Rp>{}) && ...),
+ "each argument type must be a complete class or an unbounded array");
+#endif
+ };
// Let C denote the same type, if any, as common_type_t<T1, T2>.
// If there is such a type C, type shall denote the same type, if any,
@@ -3352,9 +3378,10 @@ template <typename _From, typename _To>
// If A and B are both rvalue reference types, ...
template<typename _Xp, typename _Yp>
- struct __common_ref_impl<_Xp&&, _Yp&&,
- _Require<is_convertible<_Xp&&, __common_ref_C<_Xp, _Yp>>,
- is_convertible<_Yp&&, __common_ref_C<_Xp, _Yp>>>>
+ struct __common_ref_impl<_Xp&&, _Yp&&, _Require<
+ typename __is_convertible_helper<_Xp&&, __common_ref_C<_Xp, _Yp>>::type,
+ typename __is_convertible_helper<_Yp&&, __common_ref_C<_Xp, _Yp>>::type
+ >>
{ using type = __common_ref_C<_Xp, _Yp>; };
// let D be COMMON-REF(const X&, Y&)
@@ -3363,8 +3390,9 @@ template <typename _From, typename _To>
// If A is an rvalue reference and B is an lvalue reference, ...
template<typename _Xp, typename _Yp>
- struct __common_ref_impl<_Xp&&, _Yp&,
- _Require<is_convertible<_Xp&&, __common_ref_D<_Xp, _Yp>>>>
+ struct __common_ref_impl<_Xp&&, _Yp&, _Require<
+ typename __is_convertible_helper<_Xp&&, __common_ref_D<_Xp, _Yp>>::type
+ >>
{ using type = __common_ref_D<_Xp, _Yp>; };
// If A is an lvalue reference and B is an rvalue reference, ...
@@ -3411,7 +3439,12 @@ template <typename _From, typename _To>
// If sizeof...(T) is one ...
template<typename _Tp0>
struct common_reference<_Tp0>
- { using type = _Tp0; };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp0>{}),
+ "each argument type must be a complete class or an unbounded array");
+
+ using type = _Tp0;
+ };
template<typename _Tp1, typename _Tp2, int _Bullet = 1, typename = void>
struct __common_reference_impl
@@ -3422,7 +3455,12 @@ template <typename _From, typename _To>
template<typename _Tp1, typename _Tp2>
struct common_reference<_Tp1, _Tp2>
: __common_reference_impl<_Tp1, _Tp2>
- { };
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp1>{}),
+ "each argument type must be a complete class or an unbounded array");
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp2>{}),
+ "each argument type must be a complete class or an unbounded array");
+ };
// If T1 and T2 are reference types and COMMON-REF(T1, T2) is well-formed, ...
template<typename _Tp1, typename _Tp2>
diff --git a/libstdc++-v3/testsuite/20_util/common_reference/incomplete_basic_common_neg.cc b/libstdc++-v3/testsuite/20_util/common_reference/incomplete_basic_common_neg.cc
new file mode 100644
index 0000000..9724ad0
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/common_reference/incomplete_basic_common_neg.cc
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++20 } }
+
+// Copyright (C) 2020 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;
+
+template <>
+struct std::basic_common_reference<X, X> {
+ using type = int;
+};
+
+void test01()
+{
+ std::common_reference<X>(); // { dg-error "required from here" }
+ std::common_reference<X, X>(); // { dg-error "required from here" }
+ std::common_reference<X, X, X>(); // { dg-error "required from here" }
+ std::common_reference<X, X, X, X>(); // { dg-error "required from here" }
+ std::common_reference<X, X, X, X, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/common_reference/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/common_reference/incomplete_neg.cc
new file mode 100644
index 0000000..c151d4a
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/common_reference/incomplete_neg.cc
@@ -0,0 +1,58 @@
+// { dg-do compile { target c++20 } }
+
+// Copyright (C) 2020 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;
+class Y {};
+
+void test01()
+{
+ std::common_reference<X>(); // { dg-error "required from here" }
+ std::common_reference<X, int>(); // { dg-error "required from here" }
+ std::common_reference<X, int, int>(); // { dg-error "required from here" }
+ std::common_reference<X, int, int, int>(); // { dg-error "required from here" }
+ std::common_reference<X, int, int, int, int>(); // { dg-error "required from here" }
+
+ std::common_reference<int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, X, int>(); // { dg-error "required from here" }
+ std::common_reference<int, X, int, int>(); // { dg-error "required from here" }
+ std::common_reference<int, X, int, int, int>(); // { dg-error "required from here" }
+
+ std::common_reference<int, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, int, X, int>(); // { dg-error "required from here" }
+ std::common_reference<int, int, X, int, int>(); // { dg-error "required from here" }
+
+ std::common_reference<int, int, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, int, int, X, int>(); // { dg-error "required from here" }
+
+ std::common_reference<int, int, int, int, X>(); // { dg-error "required from here" }
+
+ std::common_reference<X, int, int, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, X, int, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, int, X, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, int, int, X, X>(); // { dg-error "required from here" }
+
+ std::common_reference<Y, int, int, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, Y, int, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, int, Y, int, X>(); // { dg-error "required from here" }
+ std::common_reference<int, int, int, Y, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/common_type/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/common_type/incomplete_neg.cc
new file mode 100644
index 0000000..6c2641d
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/common_type/incomplete_neg.cc
@@ -0,0 +1,59 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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;
+class Y {};
+
+// Some of the following asserts require __cpp_fold_expressions to trigger
+void test01()
+{
+ std::common_type<X>(); // { dg-error "required from here" }
+ std::common_type<X, int>(); // { dg-error "required from here" }
+ std::common_type<X, int, int>(); // { dg-error "required from here" }
+ std::common_type<X, int, int, int>(); // { dg-error "required from here" }
+ std::common_type<X, int, int, int, int>(); // { dg-error "required from here" }
+
+ std::common_type<int, X>(); // { dg-error "required from here" }
+ std::common_type<int, X, int>(); // { dg-error "required from here" }
+ std::common_type<int, X, int, int>(); // { dg-error "required from here" }
+ std::common_type<int, X, int, int, int>(); // { dg-error "required from here" }
+
+ std::common_type<int, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, int, X, int>(); // { dg-error "required from here" }
+ std::common_type<int, int, X, int, int>(); // { dg-error "required from here" }
+
+ std::common_type<int, int, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, int, int, X, int>(); // { dg-error "required from here" }
+
+ std::common_type<int, int, int, int, X>(); // { dg-error "required from here" }
+
+ std::common_type<X, int, int, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, X, int, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, int, X, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, int, int, X, X>(); // { dg-error "required from here" }
+
+ std::common_type<Y, int, int, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, Y, int, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, int, Y, int, X>(); // { dg-error "required from here" }
+ std::common_type<int, int, int, Y, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc b/libstdc++-v3/testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc
index 037a92f..b3b9671 100644
--- a/libstdc++-v3/testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc
+++ b/libstdc++-v3/testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc
@@ -89,7 +89,7 @@ enum class ScEn;
enum UnscEn : int;
-struct Ukn;
+
union U
{
@@ -240,7 +240,7 @@ static_assert(is_type<std::common_type<decltype(nullptr), int (B::*)() const>,
static_assert(is_type<std::common_type<decltype(nullptr), const int B::*>,
const int B::*>(), "");
static_assert(is_type<std::common_type<Abstract&, Abstract&>, Abstract>(), "");
-static_assert(is_type<std::common_type<Ukn&, Ukn&>, Ukn>(), "");
+
static_assert(is_type<std::common_type<ImplicitTo<B&>, B&>, B>(), "");
static_assert(is_type<std::common_type<ImplicitTo<B&>&, B&&>, B>(), "");
static_assert(is_type<std::common_type<UConv1, const Abstract*&>,
@@ -254,11 +254,6 @@ static_assert(is_type<std::common_type<const Abstract&&,
const Abstract&&>, Abstract>(), "");
static_assert(is_type<std::common_type<volatile Abstract&&,
volatile Abstract&&>, Abstract>(), "");
-static_assert(is_type<std::common_type<Ukn&&, Ukn&&>, Ukn>(), "");
-static_assert(is_type<std::common_type<const Ukn&&, const Ukn&&>,
- Ukn>(), "");
-static_assert(is_type<std::common_type<volatile Ukn&&, volatile Ukn&&>,
- Ukn>(), "");
static_assert(is_type<std::common_type<X1, X2>, RX12>(), "");
static_assert(is_type<std::common_type<const X1, X2>, RX12>(), "");
@@ -280,13 +275,13 @@ static_assert(!has_type<std::common_type<U, U2>>(), "");
static_assert(!has_type<std::common_type<PrivateImplicitTo<int>, int>>(), "");
static_assert(!has_type<std::common_type<const PrivateImplicitTo<int>,
int>>(), "");
-static_assert(!has_type<std::common_type<int, Ukn>>(), "");
+
static_assert(!has_type<std::common_type<int, Abstract>>(), "");
-static_assert(!has_type<std::common_type<Ukn, Abstract>>(), "");
+
static_assert(!has_type<std::common_type<int, void>>(), "");
static_assert(!has_type<std::common_type<int, const volatile void>>(), "");
static_assert(!has_type<std::common_type<Abstract, void>>(), "");
-static_assert(!has_type<std::common_type<Ukn, void>>(), "");
+
static_assert(!has_type<std::common_type<int[4], void>>(), "");
static_assert(!has_type<std::common_type<ScEn, void>>(), "");
static_assert(!has_type<std::common_type<UnscEn, void>>(), "");
diff --git a/libstdc++-v3/testsuite/20_util/is_convertible/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_convertible/incomplete_neg.cc
new file mode 100644
index 0000000..7fe7f8b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_convertible/incomplete_neg.cc
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2020 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_convertible<X, int>(); // { dg-error "required from here" }
+ std::is_convertible<int, X>(); // { dg-error "required from here" }
+ std::is_convertible<X, X>(); // { dg-error "required from here" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc
new file mode 100644
index 0000000..9c1d2f4
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++20 } }
+
+// Copyright (C) 2020 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_convertible<X, int>(); // { dg-error "required from here" }
+ std::is_nothrow_convertible<int, X>(); // { dg-error "required from here" }
+ std::is_nothrow_convertible<X, X>(); // { dg-error "required from here" }
+}
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2021-05-07 18:00 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-06 11:20 [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type Antony Polukhin
2019-05-08 21:10 ` Jonathan Wakely
2019-05-30 6:07 ` Antony Polukhin
2019-05-30 16:38 ` Jonathan Wakely
2019-05-31 5:58 ` Antony Polukhin
2019-05-31 10:36 ` Jonathan Wakely
2019-06-06 12:19 ` Jonathan Wakely
2019-06-20 17:49 ` Antony Polukhin
2019-06-20 17:57 ` Ville Voutilainen
2019-06-20 18:56 ` Antony Polukhin
2020-08-12 8:19 ` Antony Polukhin
2020-08-19 11:29 ` Jonathan Wakely
2020-08-19 16:44 ` Antony Polukhin
2020-08-20 15:31 ` Antony Polukhin
2020-09-24 7:15 ` Antony Polukhin
2020-09-24 9:29 ` Jonathan Wakely
2020-09-24 17:53 ` Jonathan Wakely
2020-11-12 18:55 ` Antony Polukhin
2021-01-08 17:28 ` Antony Polukhin
2021-05-07 18:00 ` Antony Polukhin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).