[Bug libstdc++/83981] New: vector::resize(size_type) should not require T to be CopyInsertable when std=c++14

2018-01-22 Thread dtrebbien at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83981

Bug ID: 83981
   Summary: vector::resize(size_type) should not require T to be
CopyInsertable when std=c++14
   Product: gcc
   Version: 7.2.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: dtrebbien at gmail dot com
  Target Milestone: ---

In C++14, the requirements of vector::resize(size_type) changed. Whereas C++11
requires T to be CopyInsertable, C++14 only requires T to be MoveInsertable and
DefaultInsertable.

Prompted by investigating the Stack Overflow question "boost::optional vs
std::optional for non copyable objects"
(https://stackoverflow.com/q/48340618/196844 ), it appears that there are cases
where libstdc++ requires T to be CopyInsertable when std=c++14.

Here is a test case:


#include 

#include 

struct foo {
  foo() {}
  foo(foo&&) {}
};

int main() {
  typedef boost::optional T;
  typedef std::allocator A;
  typedef std::vector X;

  A m;
  T *p = std::allocator_traits::allocate(m, 1), v;
  // DefaultInsertable
  std::allocator_traits::construct(m, p),
std::allocator_traits::destroy(m, p);
  // MoveInsertable
  std::allocator_traits::construct(m, p, std::move(v)),
std::allocator_traits::destroy(m, p);
  // CopyInsertable - not well-formed
  //std::allocator_traits::construct(m, p, v),
std::allocator_traits::destroy(m, p);

  X a;
  a.resize(1);

  return 0;
}


This does not compile in g++ 7.2.0, which produces the error message: "error:
use of deleted function 'constexpr foo::foo(const foo&)'". The full error
output mentions that __uninitialized_move_if_noexcept_a() is being
instantiated, which instantiates __uninitialized_copy_a(), but
__uninitialized_copy_a() does not work because T is not copyable.

[Bug libstdc++/83982] New: Exception guarantee of C++14 vector::resize(size_type) is not met

2018-01-22 Thread dtrebbien at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83982

Bug ID: 83982
   Summary: Exception guarantee of C++14 vector::resize(size_type)
is not met
   Product: gcc
   Version: 7.2.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: dtrebbien at gmail dot com
  Target Milestone: ---

In [vector.capacity], C++14 mentions for `void resize(size_type sz)':

"Remarks: If an exception is thrown other than by the move constructor of a
non-CopyInsertable T there are no effects."


Testing g++ 7.2.0, I have found that if an exception is raised by the default
constructor, then there might be effects.

Here is a test case:


#include 
#include 
#include 
#include 

struct T {
  static int s_count;

  T()
: m_num(s_count++)
  {
if (s_count > 1) {
  throw std::runtime_error("too many");
}
  }

  T(T&& other)
: m_num(other.m_num)
  {
other.m_num = -1;
  }

  int m_num;
};

int T::s_count = 0;

int main() {
  std::vector a(1);
  std::cout << "a[0].m_num before = " << a[0].m_num << '\n';
  assert(a[0].m_num == 0);
  try {
a.resize(2);
  } catch (...) {
// ignore
  }
  std::cout << "a[0].m_num after = " << a[0].m_num << '\n';
  assert(a[0].m_num == 0);

  return 0;
}


I expect that a[0].m_num will be unchanged by the failed resize() call;
however, it changes to -1.

[Bug libstdc++/83981] vector::resize(size_type) should not require T to be CopyInsertable when std=c++14

2018-01-23 Thread dtrebbien at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83981

--- Comment #3 from Daniel Trebbien  ---
I would like to make a patch for this and PR 83982 if that's okay.

[Bug libstdc++/83981] vector::resize(size_type) should not require T to be CopyInsertable when std=c++14

2018-01-23 Thread dtrebbien at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83981

--- Comment #5 from Daniel Trebbien  ---
I have run into a small issue. C++11 apparently does not provide an exception
guarantee on vector::resize(size_type), whereas in C++14, the exception
guarantee is "If an exception is thrown other than by the move constructor of a
non-CopyInsertable T there are no effects."

Given that C++11 does not provide a guarantee, I was thinking that it would be
fine to implement C++14's guarantee when compiling as C++11. However, there are
several questions that I have seen on Stack Overflow alone which mention or
imply that vector::resize falls back on copying existing elements if the _Tp
move constructor is not noexcept:
https://stackoverflow.com/questions/6011428/move-constructors-and-the-strong-exception-guarantee
https://stackoverflow.com/questions/21592898/c-11-move-semantics-and-stl-containers/
https://stackoverflow.com/questions/28627348/noexcept-and-copy-move-constructors/
https://stackoverflow.com/questions/47604029/move-constructors-of-stl-containers-in-msvc-2017-are-not-marked-as-noexcept/

So, my question is, if __cplusplus is 201103L (C++11 mode), should the call to
std::__uninitialized_move_if_noexcept_a be retained, thus providing a strong
exception guarantee along the lines of "If an exception is thrown there are no
effects.", and preserving backward-compatibility. Or, is it okay to implement
C++14's exception guarantee, which is not as strong, in C++11 mode as well?

[Bug libstdc++/83981] vector::resize(size_type) should not require T to be CopyInsertable when std=c++14

2018-01-25 Thread dtrebbien at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83981

--- Comment #6 from Daniel Trebbien  ---
Created attachment 43243
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=43243&action=edit
Patch for PR 83981 and PR 83982

[Bug libstdc++/83981] vector::resize(size_type) should not require T to be CopyInsertable when std=c++14

2018-01-25 Thread dtrebbien at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83981

--- Comment #7 from Daniel Trebbien  ---
So as not to break testsuite/23_containers/vector/capacity/resize/moveable2.cc
for C++11, I decided that it would be best to keep the use of
std::__uninitialized_move_if_noexcept_a() when compiling as C++11. Please see
my proposed patch.

[Bug libstdc++/83981] vector::resize(size_type) should not require T to be CopyInsertable when std=c++14

2018-01-25 Thread dtrebbien at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83981

--- Comment #12 from Daniel Trebbien  ---
https://wg21.link/lwg2158 looks relevant, particularly this part:

"This requirement is not sufficient if an implementation is free to select copy
constructor when !is_nothrow_move_constructible::value &&
is_copy_constructible::value evaluates to true. Unfortunately,
is_copy_constructible cannot reliably determine whether T is really
copy-constructible. A class may contain public non-deleted copy constructor
whose definition does not exist or cannot be instantiated successfully (e.g.,
std::vector> has copy constructor, but this type is not
copy-constructible)."

Even though is_copy_constructible for std::vector> is
true, resizing a vector of this element type works because the std::vector move
constructor is noexcept, so the move constructor is selected.

Jonathan, I personally think that your argument in Comment 10 is persuasive.

Further, I like the suggestion in LWG 2158 to add "if
!is_nothrow_move_constructible::value && is_copy_constructible::value
then T shall be CopyInsertable into *this;" to the requirements of
vector::resize(size_type). I think that this would be required because, based
on my reading of [temp.inst], it is a well-formed program to instantiate
boost::optional, as this does not require the
instantiation of the boost::optional copy
constructor.

[Bug libstdc++/83982] Exception guarantee of C++14 vector::resize(size_type) is not met

2018-01-25 Thread dtrebbien at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83982

--- Comment #2 from Daniel Trebbien  ---
Created attachment 43247
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=43247&action=edit
Patch for PR 83982 alone

[Bug libstdc++/83981] vector::resize(size_type) should not require T to be CopyInsertable when std=c++14

2018-01-25 Thread dtrebbien at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83981

--- Comment #13 from Daniel Trebbien  ---
(In reply to Jonathan Wakely from comment #9)
> Also, if boost::optional had a noexcept move constructor it would work fine.
> This is a boost bug.
> 
> The part of the patch addressing PR 83982 seems right.

I have split out the part of the patch addressing PR 83982 and have attached
the reduced patch there.

[Bug libstdc++/83982] Exception guarantee of C++14 vector::resize(size_type) is not met

2018-02-15 Thread dtrebbien at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83982

--- Comment #3 from Daniel Trebbien  ---
Friendly reminder: I have attached a patch for this issue which I would like to
have reviewed and committed.

[Bug libstdc++/83982] Exception guarantee of C++14 vector::resize(size_type) is not met

2018-02-15 Thread dtrebbien at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83982

--- Comment #5 from Daniel Trebbien  ---
Ah! Thank you for letting me know.