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.
Sounds good to me, thanks! :-)
I suggest (this is not a joke) that the right fix is to implement noexcept(auto) as an extension (possibly available only in system headers for now), and use it inside the library.
A patch has been sent to the patch list.
Author: redi Date: Tue Jan 12 21:19:58 2016 New Revision: 232296 URL: https://gcc.gnu.org/viewcvs?rev=232296&root=gcc&view=rev Log: libstdc++/68877 Reimplement std::__is_swappable 2016-01-12 Daniel Kruegler <daniel.kruegler@gmail.com> PR libstdc++/68877 * include/std/type_traits: Following N4511, reimplement __is_swappable and __is_nothrow_swappable. Move __is_swappable to namespace std, adjust callers. Use __is_nothrow_swappable in swap. * include/bits/move.h: Use __is_nothrow_swappable in swap. * testsuite/20_util/is_nothrow_swappable/value.cc: Extend; remove __is_swappable related tests. * testsuite/20_util/is_swappable/value.cc: New. * testsuite/20_util/is_swappable/requirements/ explicit_instantiation.cc: New. * testsuite/20_util/is_swappable/requirements/typedefs.cc: New. * testsuite/25_algorithms/swap/68877.cc: New. Added: trunk/libstdc++-v3/testsuite/20_util/is_swappable/ trunk/libstdc++-v3/testsuite/20_util/is_swappable/requirements/ trunk/libstdc++-v3/testsuite/20_util/is_swappable/requirements/explicit_instantiation.cc trunk/libstdc++-v3/testsuite/20_util/is_swappable/requirements/typedefs.cc trunk/libstdc++-v3/testsuite/20_util/is_swappable/value.cc trunk/libstdc++-v3/testsuite/25_algorithms/swap/68877.cc Modified: trunk/libstdc++-v3/ChangeLog trunk/libstdc++-v3/include/bits/move.h trunk/libstdc++-v3/include/std/type_traits trunk/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/value.cc
Fixed