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.