Bug 58982 - [4.9 Regression] std::vector<std::atomic<int>> vai(10); does not compile anymore
Summary: [4.9 Regression] std::vector<std::atomic<int>> vai(10); does not compile anymore
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.9.0
: P3 normal
Target Milestone: 4.9.0
Assignee: Jonathan Wakely
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2013-11-03 18:51 UTC by vincenzo Innocente
Modified: 2013-11-09 12:39 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2013-11-04 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description vincenzo Innocente 2013-11-03 18:51:19 UTC
gcc version 4.9.0 20131011 (experimental) [trunk revision 203426] (GCC) 
ok

gcc version 4.9.0 20131102 (experimental) [trunk revision 204320] (GCC) 

cat vatom.cc
#include<vector>
#include<atomic>



int main() {

  std::vector<std::atomic<int>> vai(10);
  
  for( auto & a : vai) a=0;

  return vai[0];
}

 c++ -Ofast -std=c++11 vatom.cc
In file included from /afs/cern.ch/user/i/innocent/w4/include/c++/4.9.0/vector:60:0,
                 from vatom.cc:1:
/afs/cern.ch/user/i/innocent/w4/include/c++/4.9.0/bits/stl_algobase.h: In instantiation of 'typename __gnu_cxx::__enable_if<(! std::__is_scalar<_Tp>::__value), _OutputIterator>::__type std::__fill_n_a(_OutputIterator, _Size, const _Tp&) [with _OutputIterator = std::atomic<int>*; _Size = long unsigned int; _Tp = std::atomic<int>; typename __gnu_cxx::__enable_if<(! std::__is_scalar<_Tp>::__value), _OutputIterator>::__type = std::atomic<int>*]':
/afs/cern.ch/user/i/innocent/w4/include/c++/4.9.0/bits/stl_algobase.h:787:74:   required from '_OI std::fill_n(_OI, _Size, const _Tp&) [with _OI = std::atomic<int>*; _Size = long unsigned int; _Tp = std::atomic<int>]'
/afs/cern.ch/user/i/innocent/w4/include/c++/4.9.0/bits/stl_uninitialized.h:515:42:   required from 'static void std::__uninitialized_default_n_1<true>::__uninit_default_n(_ForwardIterator, _Size) [with _ForwardIterator = std::atomic<int>*; _Size = long unsigned int]'
/afs/cern.ch/user/i/innocent/w4/include/c++/4.9.0/bits/stl_uninitialized.h:544:33:   required from 'void std::__uninitialized_default_n(_ForwardIterator, _Size) [with _ForwardIterator = std::atomic<int>*; _Size = long unsigned int]'
/afs/cern.ch/user/i/innocent/w4/include/c++/4.9.0/bits/stl_uninitialized.h:605:50:   required from 'void std::__uninitialized_default_n_a(_ForwardIterator, _Size, std::allocator<_Tp>&) [with _ForwardIterator = std::atomic<int>*; _Size = long unsigned int; _Tp = std::atomic<int>]'
/afs/cern.ch/user/i/innocent/w4/include/c++/4.9.0/bits/stl_vector.h:1290:28:   required from 'void std::vector<_Tp, _Alloc>::_M_default_initialize(std::vector<_Tp, _Alloc>::size_type) [with _Tp = std::atomic<int>; _Alloc = std::allocator<std::atomic<int> >; std::vector<_Tp, _Alloc>::size_type = long unsigned int]'
/afs/cern.ch/user/i/innocent/w4/include/c++/4.9.0/bits/stl_vector.h:265:34:   required from 'std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const allocator_type&) [with _Tp = std::atomic<int>; _Alloc = std::allocator<std::atomic<int> >; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<std::atomic<int> >]'
vatom.cc:8:39:   required from here
/afs/cern.ch/user/i/innocent/w4/include/c++/4.9.0/bits/stl_algobase.h:740:11: error: use of deleted function 'std::atomic<int>& std::atomic<int>::operator=(const std::atomic<int>&)'
  *__first = __value;
           ^
In file included from vatom.cc:2:0:
/afs/cern.ch/user/i/innocent/w4/include/c++/4.9.0/atomic:606:15: note: declared here
       atomic& operator=(const atomic&) = delete;
               ^
Comment 1 Paolo Carlini 2013-11-04 00:39:07 UTC
Jon are you willing to help with this? I'm in the middle of too many things.

First blush, I suspect stl_uninitialized.h needs updating in the light of Jason's r203985: those __is_trivial for dispatching look very suspect!
Comment 2 Paolo Carlini 2013-11-04 01:00:50 UTC
I think at least something like this for this specific bug, but the whole file needs auditing:

Index: stl_uninitialized.h
===================================================================
--- stl_uninitialized.h (revision 204342)
+++ stl_uninitialized.h (working copy)
@@ -527,7 +527,8 @@
       typedef typename iterator_traits<_ForwardIterator>::value_type
        _ValueType;
 
-      std::__uninitialized_default_1<__is_trivial(_ValueType)>::
+      std::__uninitialized_default_1
+       <std::is_copy_constructible<_ValueType>::value>::
        __uninit_default(__first, __last);
     }
 
@@ -540,7 +541,8 @@
       typedef typename iterator_traits<_ForwardIterator>::value_type
        _ValueType;
 
-      std::__uninitialized_default_n_1<__is_trivial(_ValueType)>::
+      std::__uninitialized_default_n_1
+       <std::is_copy_constructible<_ValueType>::value>::
        __uninit_default_n(__first, __n);
     }
Comment 3 Paolo Carlini 2013-11-04 06:33:54 UTC
Well, something closer to a correct minimal fix would be is_trivial && is_copy_assignable. Jon, I think that in general in this file minimal fixes would involve && with the existing is_trivial.
Comment 4 Jonathan Wakely 2013-11-08 20:32:28 UTC
(In reply to Paolo Carlini from comment #2)
> I think at least something like this for this specific bug, but the whole
> file needs auditing:

Not only that file, but stl_algobase.h too, we compile this without complaint and then do a memmove() on atomic objects!

  std::atomic<int> a[1];
  std::atomic<int> b[1];
  std::uninitialized_copy(a,a+1, b);
Comment 5 Jonathan Wakely 2013-11-08 20:35:01 UTC
And this, which is more obviously wrong:

  std::atomic<int> a[1];
  std::atomic<int> b[1];
  std::copy(a,a+1, b);
Comment 6 Paolo Carlini 2013-11-08 20:48:40 UTC
At some point we replaced a weak (not using front-end intrinsics) version of is_pod with __is_trivial, in algos & uninitialized. At that time was safe, ins't anymore in 4.9. In principle we could minimally go back to std::is_pod. Or add to __is_trivial the required additional constraints on copy & move operations. Which seems much better.
Comment 7 Jonathan Wakely 2013-11-08 20:57:08 UTC
Yes, it's not too hard to fix properly, so I'm working on that.
Comment 8 Paolo Carlini 2013-11-08 21:07:22 UTC
Thanks!
Comment 9 Jonathan Wakely 2013-11-09 12:38:03 UTC
Author: redi
Date: Sat Nov  9 12:38:00 2013
New Revision: 204615

URL: http://gcc.gnu.org/viewcvs?rev=204615&root=gcc&view=rev
Log:
	PR libstdc++/58982
	* include/bits/stl_algobase.h (__copy_move::__copy_m): Use assertion
	to prevent using memmove() on non-assignable types.
	(__copy_move_backward::__copy_move_b): Likewise.
	* include/bits/stl_uninitialized.h (uninitialized_copy
	uninitialized_copy_n, uninitialized_fill, uninitialized_fill_n,
	__uninitialized_default, __uninitialized_default_n): Check for
	assignable as well as trivial.
	* testsuite/20_util/specialized_algorithms/uninitialized_copy/
	58982.cc: New.
	* testsuite/20_util/specialized_algorithms/uninitialized_copy_n/
	58982.cc: New.
	* testsuite/20_util/specialized_algorithms/uninitialized_fill/
	58982.cc: New.
	* testsuite/20_util/specialized_algorithms/uninitialized_fill_n/
	58982.cc: New.
	* testsuite/25_algorithms/copy/58982.cc: New.
	* testsuite/25_algorithms/copy_n/58982.cc: New.

Added:
    trunk/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/58982.cc
    trunk/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/58982.cc
    trunk/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/58982.cc
    trunk/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/58982.cc
    trunk/libstdc++-v3/testsuite/25_algorithms/copy/58982.cc
    trunk/libstdc++-v3/testsuite/25_algorithms/copy_n/58982.cc
Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/include/bits/stl_algobase.h
    trunk/libstdc++-v3/include/bits/stl_uninitialized.h
Comment 10 Jonathan Wakely 2013-11-09 12:39:16 UTC
Fixed