[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