LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 28412 - std::vector incorrectly requires CopyConstructible, Destructible and other concepts
Summary: std::vector incorrectly requires CopyConstructible, Destructible and other co...
Status: RESOLVED FIXED
Alias: None
Product: libc++
Classification: Unclassified
Component: All Bugs (show other bugs)
Version: unspecified
Hardware: All All
: P normal
Assignee: Marshall Clow (home)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-07-04 09:49 PDT by Jonathan Wakely
Modified: 2019-02-11 15:56 PST (History)
4 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Wakely 2016-07-04 09:49:06 PDT
Container requirements are all stated in terms of CopyInsertable into X, and Erasable from X, which involves indirection through the container's allocator.

The following test shows a class which can only be constructed/destroyed by its allocator, revealing that std::vector tries to construct temporaries directly without going through the allocator.

/usr/local/libcxx-head/include/c++/v1/vector:1815:24: error: call to deleted constructor of 'value_type' (aka 'X')

#include <vector>

struct Tag { };

template<typename T>
  class TaggingAllocator
  {
  public:
    using value_type = T;

    TaggingAllocator() = default;

    template<typename U>
      TaggingAllocator(const TaggingAllocator<U>&) { }

    T*
    allocate(std::size_t n) { return std::allocator<T>{}.allocate(n); }

    void
    deallocate(T* p, std::size_t n) { std::allocator<T>{}.deallocate(p, n); }

    template<typename U, typename... Args>
      void
      construct(U* p, Args&&... args)
      { ::new((void*)p) U(Tag{}, std::forward<Args>(args)...); }

    template<typename U, typename... Args>
      void
      destroy(U* p)
      { p->~U(); }
  };

template<typename T, typename U>
  bool
  operator==(const TaggingAllocator<T>&, const TaggingAllocator<U>&)
  { return true; }

template<typename T, typename U>
  bool
  operator!=(const TaggingAllocator<T>&, const TaggingAllocator<U>&)
  { return false; }

struct X
{
  // All constructors must be passed the Tag type.

  // DefaultInsertable into vector<X, TaggingAllocator<X>>,
  X(Tag) { }
  // CopyInsertable into vector<X, TaggingAllocator<X>>,
  X(Tag, const X&) { }
  // MoveInsertable into vector<X, TaggingAllocator<X>>, and
  X(Tag, X&&) { }

  // EmplaceConstructible into vector<X, TaggingAllocator<X>> from args.
  template<typename... Args>
    X(Tag, Args&&...) { }

  // not DefaultConstructible, CopyConstructible or MoveConstructible.
  X() = delete;
  X(const X&) = delete;
  X(X&&) = delete;

  // CopyAssignable.
  X& operator=(const X&) { return *this; }

  // MoveAssignable.
  X& operator=(X&&) { return *this; }

private:
  // Not Destructible.
  ~X() { }

  // Erasable from vector<X, TaggingAllocator<X>>.
  friend class TaggingAllocator<X>;
};

int main()
{
  std::vector<X, TaggingAllocator<X>> v;
  v.reserve(3);
  v.emplace_back();
  v.emplace(v.begin());
  v.emplace(v.begin(), 1, 2, 3);
}

// template class std::vector<X, TaggingAllocator<X>>;

Uncommenting the last line to explicitly instantiate the vector fails differently, presumably there are some SFINAE conditions which make invalid assumptions about the type.
Comment 1 Marshall Clow (home) 2016-07-11 16:41:25 PDT
revision 275105 fixes this for deque and vector.
Leaving this open because I need to check the other containers.
Comment 2 Marshall Clow (home) 2016-07-11 19:21:08 PDT
> // template class std::vector<X, TaggingAllocator<X>>;

> Uncommenting the last line to explicitly instantiate the vector fails differently, presumably there are some SFINAE conditions which make invalid assumptions about the type.

The code that makes this blow up is in the SFINAE for assign:

X *p = new X(Tag());
v.assign(p, p + 1);

And this fails because is_constructible<X, X&>::value is false.
Comment 3 Marshall Clow (home) 2019-02-11 15:56:57 PST
This was fixed in revision 275105 (back on Jul 11 2016)