https://gcc.gnu.org/g:52d702d72afa0ade8edfff144b45539495e4d408

commit r16-4061-g52d702d72afa0ade8edfff144b45539495e4d408
Author: Ben Wu <soggysocks...@gmail.com>
Date:   Thu Sep 18 17:25:41 2025 -0700

    libstdc++: fix element construction in std::deque::emplace [PR118087]
    
    In order to emplace a value in the middle of a deque, a temporary was
    previously constructed directly with __args... in _M_emplace_aux.
    This would not work since std::deque is allocator-aware and should
    construct elements with _Alloc_traits::construct instead before the
    element is moved.
    
    Using the suggestion in PR118087, we can define _Temporary_value
    similar to the one used in std::vector, so the temporary can be
    constructed with uses-allocator construction.
    
            PR libstdc++/118087
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/deque.tcc: Use _Temporary_value in
            _M_emplace_aux.
            * include/bits/stl_deque.h: Introduce _Temporary_value.
            * testsuite/23_containers/deque/modifiers/emplace/118087.cc:
            New test.
    
    Reviewed-by: Jonathan Wakely <jwak...@redhat.com>
    Signed-off-by: Ben Wu <soggysocks...@gmail.com>

Diff:
---
 libstdc++-v3/include/bits/deque.tcc                | 11 +++++-
 libstdc++-v3/include/bits/stl_deque.h              | 29 +++++++++++++++
 .../deque/modifiers/emplace/118087.cc              | 43 ++++++++++++++++++++++
 3 files changed, 81 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/bits/deque.tcc 
b/libstdc++-v3/include/bits/deque.tcc
index dabb6ec53659..c15b046691ea 100644
--- a/libstdc++-v3/include/bits/deque.tcc
+++ b/libstdc++-v3/include/bits/deque.tcc
@@ -664,7 +664,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       deque<_Tp, _Alloc>::
       _M_emplace_aux(iterator __pos, _Args&&... __args)
       {
-       value_type __x_copy(std::forward<_Args>(__args)...); // XXX copy
+       // We should construct this temporary while the deque is
+       // in its current state in case something in __args...
+       // depends on that state before shuffling elements around.
+       _Temporary_value __tmp(this, std::forward<_Args>(__args)...);
 #else
     typename deque<_Tp, _Alloc>::iterator
       deque<_Tp, _Alloc>::
@@ -695,7 +698,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
            __pos = this->_M_impl._M_start + __index;
            _GLIBCXX_MOVE_BACKWARD3(__pos, __back2, __back1);
          }
-       *__pos = _GLIBCXX_MOVE(__x_copy);
+#if __cplusplus >= 201103L
+       *__pos = std::move(__tmp._M_val());
+#else
+       *__pos = __x_copy;
+#endif
        return __pos;
       }
 
diff --git a/libstdc++-v3/include/bits/stl_deque.h 
b/libstdc++-v3/include/bits/stl_deque.h
index 7055641ad4ea..7cc711efca8a 100644
--- a/libstdc++-v3/include/bits/stl_deque.h
+++ b/libstdc++-v3/include/bits/stl_deque.h
@@ -2163,6 +2163,35 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       iterator
       _M_insert_aux(iterator __pos, const value_type& __x);
 #else
+      struct _Temporary_value
+      {
+       template<typename... _Args>
+         _GLIBCXX20_CONSTEXPR explicit
+         _Temporary_value(deque* __deque, _Args&&... __args) : _M_this(__deque)
+         {
+           _Alloc_traits::construct(_M_this->_M_impl, _M_ptr(),
+                                    std::forward<_Args>(__args)...);
+         }
+
+       _GLIBCXX20_CONSTEXPR
+       ~_Temporary_value()
+       { _Alloc_traits::destroy(_M_this->_M_impl, _M_ptr()); }
+
+       _GLIBCXX20_CONSTEXPR value_type&
+       _M_val() noexcept { return __tmp_val; }
+
+      private:
+       _GLIBCXX20_CONSTEXPR _Tp*
+       _M_ptr() noexcept { return std::__addressof(__tmp_val); }
+
+       union
+       {
+         _Tp __tmp_val;
+       };
+
+       deque* _M_this;
+      };
+
       iterator
       _M_insert_aux(iterator __pos, const value_type& __x)
       { return _M_emplace_aux(__pos, __x); }
diff --git 
a/libstdc++-v3/testsuite/23_containers/deque/modifiers/emplace/118087.cc 
b/libstdc++-v3/testsuite/23_containers/deque/modifiers/emplace/118087.cc
new file mode 100644
index 000000000000..3606e8899807
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/modifiers/emplace/118087.cc
@@ -0,0 +1,43 @@
+// { dg-do run { target c++11 } }
+
+// PR libstdc++/118087
+// std::deque::emplace does not do uses-allocator construction
+
+#include <deque>
+#include <scoped_allocator>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+template<typename T>
+using Alloc = __gnu_test::propagating_allocator<T, true>;
+
+struct X
+{
+  using allocator_type = Alloc<int>;
+  X() { }
+  X(const X&) { }
+  X(X&&) { }
+  X(const allocator_type& a) : alloc(a) { }
+  X(const X&, const allocator_type& a) : alloc(a) { }
+  X(X&&, const allocator_type& a) : alloc(a) { }
+
+  X& operator=(const X&) = default;
+
+  allocator_type alloc{-1};
+};
+
+int main()
+{
+  std::deque<X, std::scoped_allocator_adaptor<Alloc<X>>> d(2, Alloc<X>(50));
+  VERIFY(d[0].alloc.get_personality() == 50);
+  VERIFY(d[1].alloc.get_personality() == 50);
+
+  d.emplace(d.begin() + 1);
+  VERIFY(d[1].alloc.get_personality() == 50);
+
+  d.emplace_front();
+  VERIFY(d[0].alloc.get_personality() == 50);
+
+  d.emplace_back();
+  VERIFY(d[d.size() - 1].alloc.get_personality() == 50);
+}

Reply via email to