[Bug libstdc++/68877] New: swap for multidimensional array of int ill-formed
daniel.kruegler at googlemail dot com
gcc-bugzilla@gcc.gnu.org
Sat Dec 12 18:31:00 GMT 2015
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68877
Bug ID: 68877
Summary: swap for multidimensional array of int ill-formed
Product: gcc
Version: 6.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: daniel.kruegler at googlemail dot com
Target Milestone: ---
The following code example (A reduced form of an example from a recent LWG
issue http://cplusplus.github.io/LWG/lwg-active.html#2554)
/-----------------------------------------------
#include <utility>
int main()
{
int x[2][3];
int y[2][3];
std::swap(x, y);
}
/-----------------------------------------------
compiled with the flags
-Wall -Wextra
and targetting any of C++1z, C++14, or C++11 with or without GNU extensions is
rejected in
gcc HEAD 6.0.0 20151207 (experimental)
(but not in previous releases such as 5.2.0) with the compiler diagnostics:
<quote>
In file included from /usr/local/gcc-head/include/c++/6.0.0/bits/move.h:57:0,
from /usr/local/gcc-head/include/c++/6.0.0/bits/stl_pair.h:59,
from /usr/local/gcc-head/include/c++/6.0.0/utility:70,
from prog.cc:1:
/usr/local/gcc-head/include/c++/6.0.0/type_traits: In instantiation of
'typename
std::enable_if<std::__is_swappable_impl::__is_swappable<_Tp>::value>::type
std::swap(_Tp (&)[_Nm], _Tp (&)[_Nm]) [with _Tp = int [2]; long unsigned int
_Nm = 1ul; typename
std::enable_if<std::__is_swappable_impl::__is_swappable<_Tp>::value>::type =
void]':
prog.cc:8:17: required from here
/usr/local/gcc-head/include/c++/6.0.0/type_traits:2594:27: error: no matching
function for call to 'swap(int [2], int [2])'
noexcept(noexcept(swap(*__a, *__b)));
~~~~^~~~~~~~~~~~
In file included from
/usr/local/gcc-head/include/c++/6.0.0/bits/stl_pair.h:59:0,
from /usr/local/gcc-head/include/c++/6.0.0/utility:70,
from prog.cc:1:
/usr/local/gcc-head/include/c++/6.0.0/bits/move.h:179:5: note: candidate:
template<class _Tp> typename
std::enable_if<std::__and_<std::is_move_constructible<_Tp>,
std::is_move_assignable<_Tp> >::value>::type std::swap(_Tp&, _Tp&)
swap(_Tp& __a, _Tp& __b)
^~~~
/usr/local/gcc-head/include/c++/6.0.0/bits/move.h:179:5: note: template
argument deduction/substitution failed:
/usr/local/gcc-head/include/c++/6.0.0/bits/move.h: In substitution of
'template<class _Tp> typename
std::enable_if<std::__and_<std::is_move_constructible<_Tp>,
std::is_move_assignable<_Tp> >::value>::type std::swap(_Tp&, _Tp&) [with _Tp =
int [2]]':
/usr/local/gcc-head/include/c++/6.0.0/type_traits:2594:27: required from
'typename
std::enable_if<std::__is_swappable_impl::__is_swappable<_Tp>::value>::type
std::swap(_Tp (&)[_Nm], _Tp (&)[_Nm]) [with _Tp = int [2]; long unsigned int
_Nm = 1ul; typename
std::enable_if<std::__is_swappable_impl::__is_swappable<_Tp>::value>::type =
void]'
prog.cc:8:17: required from here
/usr/local/gcc-head/include/c++/6.0.0/bits/move.h:179:5: error: no type named
'type' in 'struct std::enable_if<false, void>'
In file included from /usr/local/gcc-head/include/c++/6.0.0/bits/move.h:57:0,
from /usr/local/gcc-head/include/c++/6.0.0/bits/stl_pair.h:59,
from /usr/local/gcc-head/include/c++/6.0.0/utility:70,
from prog.cc:1:
/usr/local/gcc-head/include/c++/6.0.0/type_traits: In instantiation of
'typename
std::enable_if<std::__is_swappable_impl::__is_swappable<_Tp>::value>::type
std::swap(_Tp (&)[_Nm], _Tp (&)[_Nm]) [with _Tp = int [2]; long unsigned int
_Nm = 1ul; typename
std::enable_if<std::__is_swappable_impl::__is_swappable<_Tp>::value>::type =
void]':
prog.cc:8:17: required from here
/usr/local/gcc-head/include/c++/6.0.0/type_traits:2594:27: error: no matching
function for call to 'swap(int [2], int [2])'
noexcept(noexcept(swap(*__a, *__b)));
~~~~^~~~~~~~~~~~
In file included from
/usr/local/gcc-head/include/c++/6.0.0/bits/stl_pair.h:59:0,
from /usr/local/gcc-head/include/c++/6.0.0/utility:70,
from prog.cc:1:
/usr/local/gcc-head/include/c++/6.0.0/bits/move.h:179:5: note: candidate:
template<class _Tp> typename
std::enable_if<std::__and_<std::is_move_constructible<_Tp>,
std::is_move_assignable<_Tp> >::value>::type std::swap(_Tp&, _Tp&)
swap(_Tp& __a, _Tp& __b)
^~~~
/usr/local/gcc-head/include/c++/6.0.0/bits/move.h:179:5: note: template
argument deduction/substitution failed:
/usr/local/gcc-head/include/c++/6.0.0/bits/move.h: In substitution of
'template<class _Tp> typename
std::enable_if<std::__and_<std::is_move_constructible<_Tp>,
std::is_move_assignable<_Tp> >::value>::type std::swap(_Tp&, _Tp&) [with _Tp =
int [2]]':
/usr/local/gcc-head/include/c++/6.0.0/type_traits:2594:27: required from
'typename
std::enable_if<std::__is_swappable_impl::__is_swappable<_Tp>::value>::type
std::swap(_Tp (&)[_Nm], _Tp (&)[_Nm]) [with _Tp = int [2]; long unsigned int
_Nm = 1ul; typename
std::enable_if<std::__is_swappable_impl::__is_swappable<_Tp>::value>::type =
void]'
prog.cc:8:17: required from here
/usr/local/gcc-head/include/c++/6.0.0/bits/move.h:179:5: error: no type named
'type' in 'struct std::enable_if<false, void>'
</quote>
It seems to me that gcc's extension usage of a constrained swap declaration
(which is generally an improvement over what the standard specifies) interacts
nastily with the currently required (but obviously defect, see issue above)
exception-specification by the Standard Library. The effect of the
expression-form swap(*__a, *__b) used in the function declaration
template<typename _Tp, size_t _Nm>
inline
typename enable_if<__is_swappable_impl::__is_swappable<_Tp>::value>::type
swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm])
noexcept(noexcept(swap(*__a, *__b)));
is, that lookup cannot yet see the just being declared swap overload for arrays
(because the declaration is not completed within the noexcept declaration),
therefore the expression
swap(*__a, *__b)
is effectively evaluated in the context of the previously declared non-array
overload:
template<typename _Tp>
inline
typename enable_if<__and_<is_move_constructible<_Tp>,
is_move_assignable<_Tp>>::value>::type
swap(_Tp&, _Tp&)
noexcept(__and_<is_nothrow_move_constructible<_Tp>,
is_nothrow_move_assignable<_Tp>>::value);
But this form is constrained in regard to is_move_constructible<_Tp> and
is_move_assignable<_Tp>, none of which can evaluate to true for arrays.
A possible fix would be to (a) remove the swap constraints (which presumably
has other unwanted effects) or (b) replace the required noexcept expression
noexcept(swap(*__a, *__b)) of the array form by
__is_nothrow_swappable<_Tp>::value as suggested in the paper
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4511.html
Being the author of that paper I'm interested to add a more complete
__is_[nothrow_]swappable to libstdc++ that would also work for this example. So
feel free to assign me to this bug.
More information about the Gcc-bugs
mailing list