On 24/02/19 15:46 +0000, Jonathan Wakely wrote:
On 21/02/19 20:47 +0000, Jonathan Wakely wrote:
On 05/02/19 14:45 +0000, Jonathan Wakely wrote:
This fixes two PRs, one trivial (don't use C++17 features in C++11
mode) and one more serious (don't require MoveInsertable when we
should only need CopyInsertable).

It would be nice to rely on if-constexpr in C++11 mode, but it causes
clang warnings, complicates testcase bisection/reduction, and causes
users to file bogus bug reports. So let's just avoid it.

Tested powerpc64le-linux, committed to trunk.



commit 51908e56bd32b5f89bc909193c3da957de01c3e0
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Tue Feb 5 11:50:18 2019 +0000

 PR libstdc++/89130 restore support for non-MoveConstructible types
 The changes to "relocate" std::vector elements can lead to new errors
 outside the immediate context, because moving the elements to new
 storage no longer makes use of the move-if-noexcept utilities. This
 means that types with deleted moves no longer degenerate to copies, but
 are just ill-formed. The errors happen while instantiating the
 noexcept-specifier for __relocate_object_a, when deciding whether to try
 to relocate.
 This patch introduces indirections to avoid the ill-formed
 instantiations of std::__relocate_object_a. In order to avoid using
 if-constexpr prior to C++17 this is done by tag dispatching. After this
 patch all uses of std::__relocate_a are guarded by checks that will
 support sensible code (i.e. code not using custom allocators that fool
 the new checks).
         PR libstdc++/89130
         * include/bits/alloc_traits.h (__is_copy_insertable_impl): Rename to
         __is_alloc_insertable_impl. Replace single type member with two
         members, one for each of copy and move insertable.
         (__is_move_insertable): New trait for internal use.
         * include/bits/stl_vector.h (vector::_S_nothrow_relocate(true_type))
         (vector::_S_nothrow_relocate(true_type)): New functions to
         conditionally check if __relocate_a can throw.
         (vector::_S_use_relocate()): Dispatch to _S_nothrow_relocate based
         on __is_move_insertable.
         (vector::_S_do_relocate): New overloaded functions to conditionally
         call __relocate_a.
         (vector::_S_relocate): New function that dispatches to _S_do_relocate
         based on _S_use_relocate.
         * include/bits/vector.tcc (vector::reserve, vector::_M_realloc_insert)
         (vector::_M_default_append): Call _S_relocate instead of __relocate_a.
         * testsuite/23_containers/vector/modifiers/push_back/89130.cc: New.

diff --git a/libstdc++-v3/include/bits/alloc_traits.h 
b/libstdc++-v3/include/bits/alloc_traits.h
index ed61ce845f8..3b0c16fbf64 100644
--- a/libstdc++-v3/include/bits/alloc_traits.h
+++ b/libstdc++-v3/include/bits/alloc_traits.h
@@ -577,14 +577,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
  }

template<typename _Alloc>
-    class __is_copy_insertable_impl
+    class __is_alloc_insertable_impl
  {
-      typedef allocator_traits<_Alloc> _Traits;
+      using _Traits = allocator_traits<_Alloc>;
+      using value_type = typename _Traits::value_type;

-      template<typename _Up, typename
+      template<typename _Up, typename _Tp = __remove_cvref_t<_Up>,
+              typename
               = decltype(_Traits::construct(std::declval<_Alloc&>(),
-                                            std::declval<_Up*>(),
-                                            std::declval<const _Up&>()))>
+                                            std::declval<_Tp*>(),
+                                            std::declval<_Up>()))>
        static true_type
        _M_select(int);

@@ -593,13 +595,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        _M_select(...);

  public:
-      typedef decltype(_M_select<typename _Alloc::value_type>(0)) type;
+      using copy = decltype(_M_select<const value_type&>(0));
+      using move = decltype(_M_select<value_type>(0));

This caused another regression, fixed by the attached patch.

That patch doesn't work with Clang because I made the members
protected and forgot to make them public again (and GCC doesn't cre,
only Clang notices).

Aaaand another patch for Clang, because my test using Clang was flawed
and only tested std::allocator, which is handled by the partial
specialization. These problems are not found using G++ because of the
numerous bugs with access control in templates.

Tested powerpc64le-linux, committed to trunk.


commit f4f6e96aca78d6bfe90dab9b0fd7b94a9e31f241
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Tue Feb 26 16:56:36 2019 +0000

    PR libstdc++/89416 fix alloc insertable trait for clang (again)
    
            PR libstdc++/89416
            * include/bits/alloc_traits.h (__is_alloc_insertable_impl): Change
            to class template and partial specialization using void_t.
            (__is_copy_insertable, __is_move_insertable): Adjust base class.

diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h
index 9a3d816c42c..b8689daf74b 100644
--- a/libstdc++-v3/include/bits/alloc_traits.h
+++ b/libstdc++-v3/include/bits/alloc_traits.h
@@ -576,32 +576,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __do_alloc_on_swap(__one, __two, __pocs());
     }
 
-  class __is_alloc_insertable_impl
-  {
-    template<typename _Alloc, typename _Up,
-	     typename _Tp = __remove_cvref_t<_Up>,
-	     typename = decltype(allocator_traits<_Alloc>::construct(
-		   std::declval<_Alloc&>(), std::declval<_Tp*>(),
-		   std::declval<_Up>()))>
-      static true_type
-      _M_select(int);
+  template<typename _Alloc, typename _Tp,
+	   typename _ValueT = __remove_cvref_t<typename _Alloc::value_type>,
+	   typename = void>
+    struct __is_alloc_insertable_impl
+    : false_type
+    { };
 
-    template<typename, typename>
-      static false_type
-      _M_select(...);
-
-  public:
-    template<typename _Alloc, typename _Tp = typename _Alloc::value_type>
-      using copy = decltype(_M_select<_Alloc, const _Tp&>(0));
-
-    template<typename _Alloc, typename _Tp = typename _Alloc::value_type>
-      using move = decltype(_M_select<_Alloc, _Tp>(0));
-  };
+  template<typename _Alloc, typename _Tp, typename _ValueT>
+    struct __is_alloc_insertable_impl<_Alloc, _Tp, _ValueT,
+      __void_t<decltype(allocator_traits<_Alloc>::construct(
+		   std::declval<_Alloc&>(), std::declval<_ValueT*>(),
+		   std::declval<_Tp>()))>>
+    : true_type
+    { };
 
   // true if _Alloc::value_type is CopyInsertable into containers using _Alloc
+  // (might be wrong if _Alloc::construct exists but is not constrained,
+  // i.e. actually trying to use it would still be invalid. Use with caution.)
   template<typename _Alloc>
     struct __is_copy_insertable
-    : __is_alloc_insertable_impl::template copy<_Alloc>
+    : __is_alloc_insertable_impl<_Alloc,
+				 typename _Alloc::value_type const&>::type
     { };
 
   // std::allocator<_Tp> just requires CopyConstructible
@@ -611,9 +607,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   // true if _Alloc::value_type is MoveInsertable into containers using _Alloc
+  // (might be wrong if _Alloc::construct exists but is not constrained,
+  // i.e. actually trying to use it would still be invalid. Use with caution.)
   template<typename _Alloc>
     struct __is_move_insertable
-    : __is_alloc_insertable_impl::template move<_Alloc>
+    : __is_alloc_insertable_impl<_Alloc, typename _Alloc::value_type>::type
     { };
 
   // std::allocator<_Tp> just requires MoveConstructible

Reply via email to