<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - std::vector does not satisfy container.requirements.general clause 8"
   href="https://bugs.llvm.org/show_bug.cgi?id=37694">37694</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>std::vector does not satisfy container.requirements.general clause 8
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libc++
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>6.0
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>All
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>All Bugs
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedclangbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>sdconsta@syr.edu
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org, mclow.lists@gmail.com
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Clause 23.2.1.8 of n4140 states that for containers which obtain memory using
an allocator, "Move constructors obtain an allocator by move construction from
the allocator belonging to the container being copied." This requirements does
not hold for std::vector:

#include <memory>
#include <forward_list>
#include <vector>
#include <map>
#include <iostream>

template <typename T>
class my_allocator {
  std::allocator<T> __alloc;

public:
  using value_type = T;
  using propagate_on_container_move_assignment = std::true_type;

  my_allocator() = default;
  my_allocator(const my_allocator &other) : __alloc(other.__alloc) {
    std::cout << "copy constructor\n";
  }
  my_allocator(my_allocator &&other) noexcept : __alloc(other.__alloc) {
    std::cout << "move constructor\n";
  }

  value_type *allocate(std::size_t n) {
    return __alloc.allocate(n);
  }
  void deallocate(value_type *p, std::size_t n) {
    __alloc.deallocate(p, n);
  }
};

int main() {
  std::forward_list<int, my_allocator<int>> l = {1, 2, 3, 4};
  auto l1 = std::move(l);
  std::map<int, int, std::less<int>, my_allocator<std::pair<const int, int>>> m
= {{1, 2}, {3, 4}};
  auto m1 = std::move(m);
  std::vector<int, my_allocator<int>> v = {1, 2, 3, 4};
  auto v1 = std::move(v);
}

(compiled only with -std=c++14 on clang++) prints:

move constructor
move constructor
copy constructor

If we instead delete the copy constructor, clang emits

/usr/local/Cellar/llvm/6.0.0/include/c++/v1/memory:2097:9: error: call to
deleted constructor of 'my_allocator<int>'
      : __value_(_VSTD::forward<_Up>(__u)){};
        ^        ~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/Cellar/llvm/6.0.0/include/c++/v1/memory:2197:42: note: in
instantiation of function template specialization
'std::__1::__compressed_pair_elem<my_allocator<int>, 1,
      false>::__compressed_pair_elem<const my_allocator<int> &, void>'
requested here
      : _Base1(std::forward<_U1>(__t1)), _Base2(std::forward<_U2>(__t2)) {}
                                         ^
/usr/local/Cellar/llvm/6.0.0/include/c++/v1/vector:432:7: note: in
instantiation of function template specialization
'std::__1::__compressed_pair<int *, my_allocator<int>
      >::__compressed_pair<nullptr_t, const my_allocator<int> &>' requested
here
      __end_cap_(nullptr, __a)
      ^
/usr/local/Cellar/llvm/6.0.0/include/c++/v1/vector:1242:7: note: in
instantiation of member function 'std::__1::__vector_base<int,
my_allocator<int> >::__vector_base' requested here
    : __base(_VSTD::move(__x.__alloc()))
      ^
test.cpp:35:13: note: in instantiation of member function
'std::__1::vector<int, my_allocator<int> >::vector' requested here
  auto v1 = std::move(v);
            ^
test.cpp:15:3: note: 'my_allocator' has been explicitly marked deleted here
  my_allocator(const my_allocator &) = delete;
  ^
1 error generated.

I believe the problem is that there is no constructor for __vector_base which
accepts an rvalue reference to the allocator. Hence the copy constructor is
being called instead.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>