[patch libstdc++] Fix assignability check in uninitialized_copy
Jonathan Wakely
jwakely@redhat.com
Fri Jan 9 18:03:00 GMT 2015
On 28/12/14 13:47 +0100, Eelis wrote:
>On 2014-12-28 00:18, Eelis wrote:
>>Trivial fix attached.
>
>Please don't commit this patch.
>
>I just noticed that the assignability test is wrong in an additional way: it should look at assignability of /output/ elements, not /input/ elements.
>
>As a result, this code is currently rejected (because uninitialized_copy doesn't notice in time that chars can't be assigned to Xs):
>
> struct X
> {
> X() = default;
> X(char) {}
> X(X const &) = default;
> X & operator=(X const&) = default;
>
> X & operator=(char) = delete;
> };
>
> #include <memory>
>
> int main()
> {
> char a[100];
> X b[100];
>
> std::uninitialized_copy(a, a+10, b);
> }
>
>Updated fix attached. With it, the code is accepted again. Testing as we speak.
>Index: stl_uninitialized.h
>===================================================================
>--- stl_uninitialized.h (revision 219070)
>+++ stl_uninitialized.h (working copy)
>@@ -104,30 +104,30 @@
> */
> template<typename _InputIterator, typename _ForwardIterator>
> inline _ForwardIterator
> uninitialized_copy(_InputIterator __first, _InputIterator __last,
> _ForwardIterator __result)
> {
> typedef typename iterator_traits<_InputIterator>::value_type
> _ValueType1;
> typedef typename iterator_traits<_ForwardIterator>::value_type
> _ValueType2;
> #if __cplusplus < 201103L
> const bool __assignable = true;
> #else
> // trivial types can have deleted assignment
>- typedef typename iterator_traits<_InputIterator>::reference _RefType;
>- const bool __assignable = is_assignable<_ValueType1, _RefType>::value;
>+ typedef typename iterator_traits<_ForwardIterator>::reference _RefType;
>+ const bool __assignable = is_assignable<_RefType, _ValueType1>::value;
> #endif
This is still wrong, because it tests for assigning an rvalue to the
result sequence, but dereferencing the _InputIterator doesn't
necessarily produce an rvalue, and the output type might behave
differently for assignment from lvalues and rvalues.
My first attempt to fix it was simply:
#else
// trivial types can have deleted assignment
typedef typename iterator_traits<_InputIterator>::reference _RefType;
- const bool __assignable = is_assignable<_ValueType1, _RefType>::value;
+ const bool __assignable = is_assignable<_ValueType2, _RefType>::value;
#endif
But even that is wrong if the target type has a ref-qualified
assignment from the source type. The attached patch should be correct.
Tested x86_64-linux, committed to trunk and 4.9.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: patch.txt
Type: text/x-patch
Size: 3093 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/libstdc++/attachments/20150109/ef526b55/attachment.bin>
More information about the Libstdc++
mailing list